Merge pull request #11167 from NixOS/repl-test-rejiggle

Fix repl test for `buildReadlineNoMarkdown`
This commit is contained in:
Robert Hensing 2024-07-27 00:55:57 +02:00 committed by GitHub
commit 861bd102a6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
52 changed files with 302 additions and 157 deletions

View file

@ -1,21 +1,23 @@
#include "markdown.hh" #include "markdown.hh"
#include "util.hh" #include "environment-variables.hh"
#include "error.hh"
#include "finally.hh" #include "finally.hh"
#include "terminal.hh" #include "terminal.hh"
#if HAVE_LOWDOWN #if HAVE_LOWDOWN
# include <sys/queue.h> # include <sys/queue.h>
# include <lowdown.h> # include <lowdown.h>
#endif #endif
namespace nix { namespace nix {
std::string renderMarkdownToTerminal(std::string_view markdown)
{
#if HAVE_LOWDOWN #if HAVE_LOWDOWN
static std::string doRenderMarkdownToTerminal(std::string_view markdown)
{
int windowWidth = getWindowSize().second; int windowWidth = getWindowSize().second;
struct lowdown_opts opts { struct lowdown_opts opts
{
.type = LOWDOWN_TERM, .type = LOWDOWN_TERM,
.maxdepth = 20, .maxdepth = 20,
.cols = (size_t) std::max(windowWidth - 5, 60), .cols = (size_t) std::max(windowWidth - 5, 60),
@ -51,9 +53,21 @@ std::string renderMarkdownToTerminal(std::string_view markdown)
throw Error("allocation error while rendering Markdown"); throw Error("allocation error while rendering Markdown");
return filterANSIEscapes(std::string(buf->data, buf->size), !isTTY()); return filterANSIEscapes(std::string(buf->data, buf->size), !isTTY());
#else
return std::string(markdown);
#endif
} }
std::string renderMarkdownToTerminal(std::string_view markdown)
{
if (auto e = getEnv("_NIX_TEST_RAW_MARKDOWN"); e && *e == "1")
return std::string(markdown);
else
return doRenderMarkdownToTerminal(markdown);
} }
#else
std::string renderMarkdownToTerminal(std::string_view markdown)
{
return std::string(markdown);
}
#endif
} // namespace nix

View file

@ -1,10 +1,17 @@
#pragma once #pragma once
///@file ///@file
#include "types.hh" #include <string_view>
namespace nix { namespace nix {
/**
* Render the given Markdown text to the terminal.
*
* If Nix is compiled without Markdown support, this function will return the input text as-is.
*
* The renderer takes into account the terminal width, and wraps text accordingly.
*/
std::string renderMarkdownToTerminal(std::string_view markdown); std::string renderMarkdownToTerminal(std::string_view markdown);
} }

View file

@ -19,6 +19,7 @@ extern "C" {
#include "repl-interacter.hh" #include "repl-interacter.hh"
#include "file-system.hh" #include "file-system.hh"
#include "repl.hh" #include "repl.hh"
#include "environment-variables.hh"
namespace nix { namespace nix {
@ -175,10 +176,23 @@ bool ReadlineLikeInteracter::getLine(std::string & input, ReplPromptType promptT
return true; return true;
} }
// editline doesn't echo the input to the output when non-interactive, unlike readline
// this results in a different behavior when running tests. The echoing is
// quite useful for reading the test output, so we add it here.
if (auto e = getEnv("_NIX_TEST_REPL_ECHO"); s && e && *e == "1")
{
#ifndef USE_READLINE
// This is probably not right for multi-line input, but we don't use that
// in the characterisation tests, so it's fine.
std::cout << promptForType(promptType) << s << std::endl;
#endif
}
if (!s) if (!s)
return false; return false;
input += s; input += s;
input += '\n'; input += '\n';
return true; return true;
} }

View file

@ -217,7 +217,7 @@ ReplExitStatus NixRepl::mainLoop()
case ProcessLineResult::PromptAgain: case ProcessLineResult::PromptAgain:
break; break;
default: default:
abort(); unreachable();
} }
} catch (ParseError & e) { } catch (ParseError & e) {
if (e.msg().find("unexpected end of file") != std::string::npos) { if (e.msg().find("unexpected end of file") != std::string::npos) {

View file

@ -134,7 +134,7 @@ std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v
return {SourcePath{path.accessor, CanonPath(fn.substr(0, colon))}, lineno}; return {SourcePath{path.accessor, CanonPath(fn.substr(0, colon))}, lineno};
} catch (std::invalid_argument & e) { } catch (std::invalid_argument & e) {
fail(); fail();
abort(); unreachable();
} }
} }

View file

@ -86,7 +86,9 @@ void fixupBoehmStackPointer(void ** sp_ptr, void * _pthread_id)
{ {
void *& sp = *sp_ptr; void *& sp = *sp_ptr;
auto pthread_id = reinterpret_cast<pthread_t>(_pthread_id); auto pthread_id = reinterpret_cast<pthread_t>(_pthread_id);
# ifndef __APPLE__
pthread_attr_t pattr; pthread_attr_t pattr;
# endif
size_t osStackSize; size_t osStackSize;
// The low address of the stack, which grows down. // The low address of the stack, which grows down.
void * osStackLimit; void * osStackLimit;

View file

@ -149,7 +149,7 @@ std::string_view showType(ValueType type, bool withArticle)
case nFloat: return WA("a", "float"); case nFloat: return WA("a", "float");
case nThunk: return WA("a", "thunk"); case nThunk: return WA("a", "thunk");
} }
abort(); unreachable();
} }
@ -780,7 +780,7 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr &
case ReplExitStatus::Continue: case ReplExitStatus::Continue:
break; break;
default: default:
abort(); unreachable();
} }
} }
} }
@ -1149,7 +1149,7 @@ inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v, const PosIdx po
void Expr::eval(EvalState & state, Env & env, Value & v) void Expr::eval(EvalState & state, Env & env, Value & v)
{ {
abort(); unreachable();
} }
@ -1582,7 +1582,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
.withFrame(*fun.payload.lambda.env, lambda) .withFrame(*fun.payload.lambda.env, lambda)
.debugThrow(); .debugThrow();
} }
abort(); // can't happen unreachable();
} }
} }

View file

@ -25,7 +25,7 @@ std::ostream & operator <<(std::ostream & str, const SymbolStr & symbol)
void Expr::show(const SymbolTable & symbols, std::ostream & str) const void Expr::show(const SymbolTable & symbols, std::ostream & str) const
{ {
abort(); unreachable();
} }
void ExprInt::show(const SymbolTable & symbols, std::ostream & str) const void ExprInt::show(const SymbolTable & symbols, std::ostream & str) const
@ -271,7 +271,7 @@ std::string showAttrPath(const SymbolTable & symbols, const AttrPath & attrPath)
void Expr::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void Expr::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
{ {
abort(); unreachable();
} }
void ExprInt::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) void ExprInt::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)

View file

@ -426,7 +426,7 @@ static void prim_typeOf(EvalState & state, const PosIdx pos, Value * * args, Val
t = args[0]->external()->typeOf(); t = args[0]->external()->typeOf();
break; break;
case nFloat: t = "float"; break; case nFloat: t = "float"; break;
case nThunk: abort(); case nThunk: unreachable();
} }
v.mkString(t); v.mkString(t);
} }

View file

@ -94,7 +94,7 @@ void printAmbiguous(
break; break;
default: default:
printError("Nix evaluator internal error: printAmbiguous: invalid value type"); printError("Nix evaluator internal error: printAmbiguous: invalid value type");
abort(); unreachable();
} }
} }

View file

@ -475,7 +475,7 @@ private:
else else
output << "primop"; output << "primop";
} else { } else {
abort(); unreachable();
} }
output << "»"; output << "»";
@ -504,7 +504,7 @@ private:
if (options.ansiColors) if (options.ansiColors)
output << ANSI_NORMAL; output << ANSI_NORMAL;
} else { } else {
abort(); unreachable();
} }
} }

View file

@ -7,6 +7,7 @@
#include "types.hh" #include "types.hh"
#include "chunked-vector.hh" #include "chunked-vector.hh"
#include "error.hh"
namespace nix { namespace nix {
@ -113,7 +114,7 @@ public:
SymbolStr operator[](Symbol s) const SymbolStr operator[](Symbol s) const
{ {
if (s.id == 0 || s.id > store.size()) if (s.id == 0 || s.id > store.size())
abort(); unreachable();
return SymbolStr(store[s.id - 1]); return SymbolStr(store[s.id - 1]);
} }

View file

@ -285,7 +285,7 @@ public:
if (invalidIsThunk) if (invalidIsThunk)
return nThunk; return nThunk;
else else
abort(); unreachable();
} }
inline void finishValue(InternalType newType, Payload newPayload) inline void finishValue(InternalType newType, Payload newPayload)

View file

@ -33,7 +33,7 @@ nlohmann::json attrsToJSON(const Attrs & attrs)
json[attr.first] = *v; json[attr.first] = *v;
} else if (auto v = std::get_if<Explicit<bool>>(&attr.second)) { } else if (auto v = std::get_if<Explicit<bool>>(&attr.second)) {
json[attr.first] = v->t; json[attr.first] = v->t;
} else abort(); } else unreachable();
} }
return json; return json;
} }
@ -99,7 +99,7 @@ std::map<std::string, std::string> attrsToQuery(const Attrs & attrs)
query.insert_or_assign(attr.first, *v); query.insert_or_assign(attr.first, *v);
} else if (auto v = std::get_if<Explicit<bool>>(&attr.second)) { } else if (auto v = std::get_if<Explicit<bool>>(&attr.second)) {
query.insert_or_assign(attr.first, v->t ? "1" : "0"); query.insert_or_assign(attr.first, v->t ? "1" : "0");
} else abort(); } else unreachable();
} }
return query; return query;
} }

View file

@ -36,7 +36,7 @@ Logger * makeDefaultLogger() {
return logger; return logger;
} }
default: default:
abort(); unreachable();
} }
} }

View file

@ -36,7 +36,7 @@ public:
Co init() override; Co init() override;
Co realisationFetched(std::shared_ptr<const Realisation> outputInfo, nix::ref<nix::Store> sub); Co realisationFetched(std::shared_ptr<const Realisation> outputInfo, nix::ref<nix::Store> sub);
void timedOut(Error && ex) override { abort(); }; void timedOut(Error && ex) override { unreachable(); };
std::string key() override; std::string key() override;

View file

@ -400,12 +400,12 @@ public:
virtual void handleChildOutput(Descriptor fd, std::string_view data) virtual void handleChildOutput(Descriptor fd, std::string_view data)
{ {
abort(); unreachable();
} }
virtual void handleEOF(Descriptor fd) virtual void handleEOF(Descriptor fd)
{ {
abort(); unreachable();
} }
void trace(std::string_view s); void trace(std::string_view s);

View file

@ -50,7 +50,7 @@ public:
PathSubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt); PathSubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
~PathSubstitutionGoal(); ~PathSubstitutionGoal();
void timedOut(Error && ex) override { abort(); }; void timedOut(Error && ex) override { unreachable(); };
/** /**
* We prepend "a$" to the key name to ensure substitution goals * We prepend "a$" to the key name to ensure substitution goals

View file

@ -216,7 +216,7 @@ void Worker::childStarted(GoalPtr goal, const std::set<MuxablePipePollState::Com
nrLocalBuilds++; nrLocalBuilds++;
break; break;
default: default:
abort(); unreachable();
} }
} }
} }
@ -239,7 +239,7 @@ void Worker::childTerminated(Goal * goal, bool wakeSleepers)
nrLocalBuilds--; nrLocalBuilds--;
break; break;
default: default:
abort(); unreachable();
} }
} }

View file

@ -33,7 +33,7 @@ Sink & operator << (Sink & sink, const Logger::Fields & fields)
sink << f.i; sink << f.i;
else if (f.type == Logger::Field::tString) else if (f.type == Logger::Field::tString)
sink << f.s; sink << f.s;
else abort(); else unreachable();
} }
return sink; return sink;
} }

View file

@ -559,7 +559,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
non-blocking flag from the server socket, so non-blocking flag from the server socket, so
explicitly make it blocking. */ explicitly make it blocking. */
if (fcntl(fdClient.get(), F_SETFL, fcntl(fdClient.get(), F_GETFL) & ~O_NONBLOCK) == -1) if (fcntl(fdClient.get(), F_SETFL, fcntl(fdClient.get(), F_GETFL) & ~O_NONBLOCK) == -1)
abort(); panic("Could not set non-blocking flag on client socket");
while (true) { while (true) {
try { try {

View file

@ -297,7 +297,7 @@ template<> std::string BaseSetting<SandboxMode>::to_string() const
if (value == smEnabled) return "true"; if (value == smEnabled) return "true";
else if (value == smRelaxed) return "relaxed"; else if (value == smRelaxed) return "relaxed";
else if (value == smDisabled) return "false"; else if (value == smDisabled) return "false";
else abort(); else unreachable();
} }
template<> void BaseSetting<SandboxMode>::convertToArg(Args & args, const std::string & category) template<> void BaseSetting<SandboxMode>::convertToArg(Args & args, const std::string & category)

View file

@ -164,7 +164,7 @@ public:
Cache & getCache(State & state, const std::string & uri) Cache & getCache(State & state, const std::string & uri)
{ {
auto i = state.caches.find(uri); auto i = state.caches.find(uri);
if (i == state.caches.end()) abort(); if (i == state.caches.end()) unreachable();
return i->second; return i->second;
} }
@ -211,7 +211,7 @@ public:
{ {
auto r(state->insertCache.use()(uri)(time(0))(storeDir)(wantMassQuery)(priority)); auto r(state->insertCache.use()(uri)(time(0))(storeDir)(wantMassQuery)(priority));
if (!r.next()) { abort(); } if (!r.next()) { unreachable(); }
ret.id = (int) r.getInt(0); ret.id = (int) r.getInt(0);
} }

View file

@ -165,7 +165,7 @@ void LocalDerivationGoal::killSandbox(bool getStats)
buildResult.cpuSystem = stats.cpuSystem; buildResult.cpuSystem = stats.cpuSystem;
} }
#else #else
abort(); unreachable();
#endif #endif
} }

View file

@ -45,7 +45,7 @@ bool lockFile(Descriptor desc, LockType lockType, bool wait)
if (lockType == ltRead) type = LOCK_SH; if (lockType == ltRead) type = LOCK_SH;
else if (lockType == ltWrite) type = LOCK_EX; else if (lockType == ltWrite) type = LOCK_EX;
else if (lockType == ltNone) type = LOCK_UN; else if (lockType == ltNone) type = LOCK_UN;
else abort(); else unreachable();
if (wait) { if (wait) {
while (flock(desc, type) != 0) { while (flock(desc, type) != 0) {

View file

@ -6,6 +6,8 @@
#include <vector> #include <vector>
#include <limits> #include <limits>
#include "error.hh"
namespace nix { namespace nix {
/** /**
@ -30,7 +32,7 @@ private:
auto & addChunk() auto & addChunk()
{ {
if (size_ >= std::numeric_limits<uint32_t>::max() - ChunkSize) if (size_ >= std::numeric_limits<uint32_t>::max() - ChunkSize)
abort(); unreachable();
chunks.emplace_back(); chunks.emplace_back();
chunks.back().reserve(ChunkSize); chunks.back().reserve(ChunkSize);
return chunks.back(); return chunks.back();

View file

@ -1,3 +1,5 @@
#include <algorithm>
#include "error.hh" #include "error.hh"
#include "environment-variables.hh" #include "environment-variables.hh"
#include "signals.hh" #include "signals.hh"
@ -430,4 +432,36 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s
return out; return out;
} }
/** Write to stderr in a robust and minimal way, considering that the process
* may be in a bad state.
*/
static void writeErr(std::string_view buf)
{
while (!buf.empty()) {
auto n = write(STDERR_FILENO, buf.data(), buf.size());
if (n < 0) {
if (errno == EINTR) continue;
abort();
}
buf = buf.substr(n);
}
}
void panic(std::string_view msg)
{
writeErr("\n\n" ANSI_RED "terminating due to unexpected unrecoverable internal error: " ANSI_NORMAL );
writeErr(msg);
writeErr("\n");
abort();
}
void panic(const char * file, int line, const char * func)
{
char buf[512];
int n = snprintf(buf, sizeof(buf), "Unexpected condition in %s at %s:%d", func, file, line);
if (n < 0)
panic("Unexpected condition and could not format error message");
panic(std::string_view(buf, std::min(static_cast<int>(sizeof(buf)), n)));
}
} }

View file

@ -273,4 +273,24 @@ using NativeSysError =
*/ */
void throwExceptionSelfCheck(); void throwExceptionSelfCheck();
/**
* Print a message and abort().
*/
[[noreturn]]
void panic(std::string_view msg);
/**
* Print a basic error message with source position and abort().
* Use the unreachable() macro to call this.
*/
[[noreturn]]
void panic(const char * file, int line, const char * func);
/**
* Print a basic error message with source position and abort().
*
* @note: This assumes that the logger is operational
*/
#define unreachable() (::nix::panic(__FILE__, __LINE__, __func__))
} }

View file

@ -63,7 +63,7 @@ std::string_view renderFileIngestionMethod(FileIngestionMethod method)
case FileIngestionMethod::Git: case FileIngestionMethod::Git:
return "git"; return "git";
default: default:
abort(); unreachable();
} }
} }

View file

@ -53,7 +53,7 @@ void copyRecursive(
throw Error("file '%1%' has an unsupported type", from); throw Error("file '%1%' has an unsupported type", from);
default: default:
abort(); unreachable();
} }
} }

View file

@ -201,7 +201,7 @@ std::optional<Mode> convertMode(SourceAccessor::Type type)
case SourceAccessor::tRegular: return Mode::Regular; case SourceAccessor::tRegular: return Mode::Regular;
case SourceAccessor::tDirectory: return Mode::Directory; case SourceAccessor::tDirectory: return Mode::Directory;
case SourceAccessor::tMisc: return std::nullopt; case SourceAccessor::tMisc: return std::nullopt;
default: abort(); default: unreachable();
} }
} }

View file

@ -25,7 +25,7 @@ static size_t regularHashSize(HashAlgorithm type) {
case HashAlgorithm::SHA256: return sha256HashSize; case HashAlgorithm::SHA256: return sha256HashSize;
case HashAlgorithm::SHA512: return sha512HashSize; case HashAlgorithm::SHA512: return sha512HashSize;
} }
abort(); unreachable();
} }

View file

@ -189,7 +189,7 @@ struct JSONLogger : Logger {
else if (f.type == Logger::Field::tString) else if (f.type == Logger::Field::tString)
arr.push_back(f.s); arr.push_back(f.s);
else else
abort(); unreachable();
} }
void write(const nlohmann::json & json) void write(const nlohmann::json & json)

View file

@ -260,7 +260,7 @@ std::unique_ptr<FinishSink> sourceToSink(std::function<void(Source &)> fun)
}); });
} }
if (!*coro) { abort(); } if (!*coro) { unreachable(); }
if (!cur.empty()) { if (!cur.empty()) {
CoroutineContext ctx; CoroutineContext ctx;
@ -271,12 +271,12 @@ std::unique_ptr<FinishSink> sourceToSink(std::function<void(Source &)> fun)
void finish() override void finish() override
{ {
if (!coro) return; if (!coro) return;
if (!*coro) abort(); if (!*coro) unreachable();
{ {
CoroutineContext ctx; CoroutineContext ctx;
(*coro)(true); (*coro)(true);
} }
if (*coro) abort(); if (*coro) unreachable();
} }
}; };
@ -316,7 +316,7 @@ std::unique_ptr<Source> sinkToSource(
}); });
} }
if (!*coro) { eof(); abort(); } if (!*coro) { eof(); unreachable(); }
if (pos == cur.size()) { if (pos == cur.size()) {
if (!cur.empty()) { if (!cur.empty()) {

View file

@ -7,6 +7,8 @@
#include <condition_variable> #include <condition_variable>
#include <cassert> #include <cassert>
#include "error.hh"
namespace nix { namespace nix {
/** /**
@ -47,7 +49,7 @@ public:
friend SyncBase; friend SyncBase;
Lock(SyncBase * s) : s(s), lk(s->mutex) { } Lock(SyncBase * s) : s(s), lk(s->mutex) { }
public: public:
Lock(Lock && l) : s(l.s) { abort(); } Lock(Lock && l) : s(l.s) { unreachable(); }
Lock(const Lock & l) = delete; Lock(const Lock & l) = delete;
~Lock() { } ~Lock() { }

View file

@ -40,7 +40,9 @@ public:
#endif #endif
; ;
auto count = poll(fds, 1, -1); auto count = poll(fds, 1, -1);
if (count == -1) abort(); // can't happen if (count == -1)
unreachable();
/* This shouldn't happen, but can on macOS due to a bug. /* This shouldn't happen, but can on macOS due to a bug.
See rdar://37550628. See rdar://37550628.

View file

@ -182,7 +182,7 @@ static pid_t doFork(bool allowVfork, ChildWrapperFunction & fun)
#endif #endif
if (pid != 0) return pid; if (pid != 0) return pid;
fun(); fun();
abort(); unreachable();
} }

View file

@ -1159,7 +1159,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
case cvEqual: ch = '='; break; case cvEqual: ch = '='; break;
case cvGreater: ch = '<'; break; case cvGreater: ch = '<'; break;
case cvUnavail: ch = '-'; break; case cvUnavail: ch = '-'; break;
default: abort(); default: unreachable();
} }
if (xmlOutput) { if (xmlOutput) {

View file

@ -480,7 +480,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
} }
default: default:
abort(); unreachable();
} }
} }

View file

@ -262,6 +262,23 @@ badExitCode=0
nixVersion="$(nix eval --impure --raw --expr 'builtins.nixVersion' --extra-experimental-features nix-command)" nixVersion="$(nix eval --impure --raw --expr 'builtins.nixVersion' --extra-experimental-features nix-command)"
# TODO: write a repl interacter for testing. Papering over the differences between readline / editline and between platforms is a pain.
# I couldn't get readline and editline to agree on the newline before the prompt,
# so let's just force it to be one empty line.
stripEmptyLinesBeforePrompt() {
# --null-data: treat input as NUL-terminated instead of newline-terminated
sed --null-data 's/\n\n*nix-repl>/\n\nnix-repl>/g'
}
# We don't get a final prompt on darwin, so we strip this as well.
stripFinalPrompt() {
# Strip the final prompt and/or any trailing spaces
sed --null-data \
-e 's/\(.*[^\n]\)\n\n*nix-repl>[ \n]*$/\1/' \
-e 's/[ \n]*$/\n/'
}
runRepl () { runRepl () {
# That is right, we are also filtering out the testdir _without underscores_. # That is right, we are also filtering out the testdir _without underscores_.
@ -273,8 +290,13 @@ runRepl () {
testDirNoUnderscores="${testDir//_/}" testDirNoUnderscores="${testDir//_/}"
# TODO: pass arguments to nix repl; see lang.sh # TODO: pass arguments to nix repl; see lang.sh
_NIX_TEST_RAW_MARKDOWN=1 \
_NIX_TEST_REPL_ECHO=1 \
nix repl 2>&1 \ nix repl 2>&1 \
| stripColors \ | stripColors \
| tr -d '\0' \
| stripEmptyLinesBeforePrompt \
| stripFinalPrompt \
| sed \ | sed \
-e "s@$testDir@/path/to/tests/functional@g" \ -e "s@$testDir@/path/to/tests/functional@g" \
-e "s@$testDirNoUnderscores@/path/to/tests/functional@g" \ -e "s@$testDirNoUnderscores@/path/to/tests/functional@g" \
@ -289,7 +311,10 @@ for test in $(cd "$testDir/repl"; echo *.in); do
in="$testDir/repl/$test.in" in="$testDir/repl/$test.in"
actual="$testDir/repl/$test.actual" actual="$testDir/repl/$test.actual"
expected="$testDir/repl/$test.expected" expected="$testDir/repl/$test.expected"
(cd "$testDir/repl"; set +x; runRepl 2>&1) < "$in" > "$actual" (cd "$testDir/repl"; set +x; runRepl 2>&1) < "$in" > "$actual" || {
echo "FAIL: $test (exit code $?)" >&2
badExitCode=1
}
diffAndAcceptInner "$test" "$actual" "$expected" diffAndAcceptInner "$test" "$actual" "$expected"
done done

View file

@ -1,24 +1,28 @@
Nix <nix version> Nix <nix version>
Type :? for help. Type :? for help.
nix-repl> :l doc-comments.nix
Added <number omitted> variables. Added <number omitted> variables.
Function curriedArgs nix-repl> :doc curriedArgs
… defined at Function `curriedArgs`\
/path/to/tests/functional/repl/doc-comments.nix:48:5 … defined at /path/to/tests/functional/repl/doc-comments.nix:48:5
A documented function. A documented function.
nix-repl> x = curriedArgs 1
nix-repl> "Note that users may not expect this to behave as it currently does"
"Note that users may not expect this to behave as it currently does" "Note that users may not expect this to behave as it currently does"
Function curriedArgs nix-repl> :doc x
… defined at Function `curriedArgs`\
/path/to/tests/functional/repl/doc-comments.nix:50:5 … defined at /path/to/tests/functional/repl/doc-comments.nix:50:5
The function returned by applying once The function returned by applying once
"This won't produce documentation, because we can't actually document arbitrary values" nix-repl> "This won't produce docs; no support for arbitrary values"
"This won't produce docs; no support for arbitrary values"
nix-repl> :doc x 2
error: value does not have documentation error: value does not have documentation

View file

@ -3,5 +3,5 @@
x = curriedArgs 1 x = curriedArgs 1
"Note that users may not expect this to behave as it currently does" "Note that users may not expect this to behave as it currently does"
:doc x :doc x
"This won't produce documentation, because we can't actually document arbitrary values" "This won't produce docs; no support for arbitrary values"
:doc x 2 :doc x 2

View file

@ -1,13 +1,14 @@
Nix <nix version> Nix <nix version>
Type :? for help. Type :? for help.
nix-repl> :l doc-comments.nix
Added <number omitted> variables. Added <number omitted> variables.
nix-repl> "Note that this is not yet complete"
"Note that this is not yet complete" "Note that this is not yet complete"
Function documentedFormals nix-repl> :doc documentedFormals
… defined at Function `documentedFormals`\
/path/to/tests/functional/repl/doc-comments.nix:57:5 … defined at /path/to/tests/functional/repl/doc-comments.nix:57:5
Finds x
Finds x

View file

@ -1,8 +1,7 @@
Nix <nix version> Nix <nix version>
Type :? for help. Type :? for help.
Function defined at
/path/to/tests/functional/repl/doc-comment-function.nix:2:1
A doc comment for a file that only contains a function
nix-repl> :doc import ./doc-comment-function.nix
Function defined at /path/to/tests/functional/repl/doc-comment-function.nix:2:1
A doc comment for a file that only contains a function

View file

@ -1,11 +1,11 @@
Nix <nix version> Nix <nix version>
Type :? for help. Type :? for help.
nix-repl> :l doc-comments.nix
Added <number omitted> variables. Added <number omitted> variables.
Function compact nix-repl> :doc compact
… defined at Function `compact`\
/path/to/tests/functional/repl/doc-comments.nix:18:20 … defined at /path/to/tests/functional/repl/doc-comments.nix:18:20
boom
boom

View file

@ -1,23 +1,27 @@
Nix <nix version> Nix <nix version>
Type :? for help. Type :? for help.
nix-repl> :l doc-comments.nix
Added <number omitted> variables. Added <number omitted> variables.
nix-repl> :doc constant
error: value does not have documentation error: value does not have documentation
Attribute version nix-repl> :doc lib.version
Attribute `version`
… defined at … defined at /path/to/tests/functional/repl/doc-comments.nix:30:3
/path/to/tests/functional/repl/doc-comments.nix:30:3
Immovably fixed. Immovably fixed.
Attribute empty nix-repl> :doc lib.attr.empty
Attribute `empty`
… defined at … defined at /path/to/tests/functional/repl/doc-comments.nix:33:3
/path/to/tests/functional/repl/doc-comments.nix:33:3
Unchangeably constant. Unchangeably constant.
nix-repl> :doc lib.attr.undocument
error: error:
… while evaluating the attribute 'attr.undocument' … while evaluating the attribute 'attr.undocument'
at /path/to/tests/functional/repl/doc-comments.nix:33:3: at /path/to/tests/functional/repl/doc-comments.nix:33:3:
@ -32,59 +36,65 @@ error:
| ^ | ^
Did you mean undocumented? Did you mean undocumented?
Attribute constant nix-repl> :doc (import ./doc-comments.nix).constant
Attribute `constant`
… defined at … defined at /path/to/tests/functional/repl/doc-comments.nix:27:3
/path/to/tests/functional/repl/doc-comments.nix:27:3
Firmly rigid. Firmly rigid.
Attribute version nix-repl> :doc (import ./doc-comments.nix).lib.version
Attribute `version`
… defined at … defined at /path/to/tests/functional/repl/doc-comments.nix:30:3
/path/to/tests/functional/repl/doc-comments.nix:30:3
Immovably fixed. Immovably fixed.
Attribute empty nix-repl> :doc (import ./doc-comments.nix).lib.attr.empty
Attribute `empty`
… defined at … defined at /path/to/tests/functional/repl/doc-comments.nix:33:3
/path/to/tests/functional/repl/doc-comments.nix:33:3
Unchangeably constant. Unchangeably constant.
Attribute undocumented nix-repl> :doc (import ./doc-comments.nix).lib.attr.undocumented
Attribute `undocumented`
… defined at … defined at /path/to/tests/functional/repl/doc-comments.nix:35:3
/path/to/tests/functional/repl/doc-comments.nix:35:3
No documentation found. No documentation found.
nix-repl> :doc missing
error: undefined variable 'missing' error: undefined variable 'missing'
at «string»:1:1: at «string»:1:1:
1| missing 1| missing
| ^ | ^
nix-repl> :doc constanz
error: undefined variable 'constanz' error: undefined variable 'constanz'
at «string»:1:1: at «string»:1:1:
1| constanz 1| constanz
| ^ | ^
nix-repl> :doc missing.attr
error: undefined variable 'missing' error: undefined variable 'missing'
at «string»:1:1: at «string»:1:1:
1| missing.attr 1| missing.attr
| ^ | ^
nix-repl> :doc lib.missing
error: attribute 'missing' missing error: attribute 'missing' missing
at «string»:1:1: at «string»:1:1:
1| lib.missing 1| lib.missing
| ^ | ^
nix-repl> :doc lib.missing.attr
error: attribute 'missing' missing error: attribute 'missing' missing
at «string»:1:1: at «string»:1:1:
1| lib.missing.attr 1| lib.missing.attr
| ^ | ^
nix-repl> :doc lib.attr.undocumental
error: error:
… while evaluating the attribute 'attr.undocumental' … while evaluating the attribute 'attr.undocumental'
at /path/to/tests/functional/repl/doc-comments.nix:33:3: at /path/to/tests/functional/repl/doc-comments.nix:33:3:
@ -98,5 +108,3 @@ error:
1| lib.attr.undocumental 1| lib.attr.undocumental
| ^ | ^
Did you mean undocumented? Did you mean undocumented?

View file

@ -1,11 +1,11 @@
Nix <nix version> Nix <nix version>
Type :? for help. Type :? for help.
nix-repl> :l doc-comments.nix
Added <number omitted> variables. Added <number omitted> variables.
Function floatedIn nix-repl> :doc floatedIn
… defined at Function `floatedIn`\
/path/to/tests/functional/repl/doc-comments.nix:16:5 … defined at /path/to/tests/functional/repl/doc-comments.nix:16:5
This also works.
This also works.

View file

@ -1,29 +1,29 @@
Nix <nix version> Nix <nix version>
Type :? for help. Type :? for help.
nix-repl> :l doc-comments.nix
Added <number omitted> variables. Added <number omitted> variables.
Function nonStrict nix-repl> :doc nonStrict
… defined at Function `nonStrict`\
/path/to/tests/functional/repl/doc-comments.nix:37:70 … defined at /path/to/tests/functional/repl/doc-comments.nix:37:70
My syntax is not strict, but I'm strict anyway. My syntax is not strict, but I'm strict anyway.
Function strict nix-repl> :doc strict
… defined at Function `strict`\
/path/to/tests/functional/repl/doc-comments.nix:38:63 … defined at /path/to/tests/functional/repl/doc-comments.nix:38:63
I don't have to be strict, but I am anyway. I don't have to be strict, but I am anyway.
Function strictPre nix-repl> :doc strictPre
… defined at Function `strictPre`\
/path/to/tests/functional/repl/doc-comments.nix:40:48 … defined at /path/to/tests/functional/repl/doc-comments.nix:40:48
Here's one way to do this Here's one way to do this
Function strictPost
… defined at
/path/to/tests/functional/repl/doc-comments.nix:41:53
Here's another way to do this
nix-repl> :doc strictPost
Function `strictPost`\
… defined at /path/to/tests/functional/repl/doc-comments.nix:41:53
Here's another way to do this

View file

@ -1,11 +1,11 @@
Nix <nix version> Nix <nix version>
Type :? for help. Type :? for help.
nix-repl> :l doc-comments.nix
Added <number omitted> variables. Added <number omitted> variables.
Function measurement nix-repl> :doc measurement
… defined at Function `measurement`\
/path/to/tests/functional/repl/doc-comments.nix:13:17 … defined at /path/to/tests/functional/repl/doc-comments.nix:13:17
👈 precisely this wide 👉
👈 precisely this wide 👉

View file

@ -1,15 +1,17 @@
Nix <nix version> Nix <nix version>
Type :? for help. Type :? for help.
nix-repl> :l doc-comments.nix
Added <number omitted> variables. Added <number omitted> variables.
Function multiply nix-repl> :doc multiply
… defined at Function `multiply`\
/path/to/tests/functional/repl/doc-comments.nix:10:14 … defined at /path/to/tests/functional/repl/doc-comments.nix:10:14
Perform arithmetic multiplication. It's kind of like
repeated addition, very neat.
| multiply 2 3
| => 6
Perform *arithmetic* multiplication. It's kind of like repeated **addition**, very neat.
```nix
multiply 2 3
=> 6
```

View file

@ -1,11 +1,11 @@
Nix <nix version> Nix <nix version>
Type :? for help. Type :? for help.
nix-repl> :l doc-comments.nix
Added <number omitted> variables. Added <number omitted> variables.
Function unambiguous nix-repl> :doc unambiguous
… defined at Function `unambiguous`\
/path/to/tests/functional/repl/doc-comments.nix:24:5 … defined at /path/to/tests/functional/repl/doc-comments.nix:24:5
Very close
Very close

View file

@ -1,29 +1,37 @@
Nix <nix version> Nix <nix version>
Type :? for help. Type :? for help.
nix-repl> :l pretty-print-idempotent.nix
Added <number omitted> variables. Added <number omitted> variables.
nix-repl> oneDeep
{ homepage = "https://example.com"; } { homepage = "https://example.com"; }
nix-repl> oneDeep
{ homepage = "https://example.com"; } { homepage = "https://example.com"; }
nix-repl> twoDeep
{ {
layerOne = { ... }; layerOne = { ... };
} }
nix-repl> twoDeep
{ {
layerOne = { ... }; layerOne = { ... };
} }
nix-repl> oneDeepList
[ "https://example.com" ] [ "https://example.com" ]
nix-repl> oneDeepList
[ "https://example.com" ] [ "https://example.com" ]
nix-repl> twoDeepList
[ [
[ ... ] [ ... ]
] ]
nix-repl> twoDeepList
[ [
[ ... ] [ ... ]
] ]