1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-11 13:06:01 +01:00

nix repl: Render docs for attributes

This commit is contained in:
Robert Hensing 2024-07-09 19:25:45 +02:00
parent 491b9cf415
commit d4f576b0b2
10 changed files with 237 additions and 3 deletions

View file

@ -1415,6 +1415,22 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
v = *vAttrs;
}
Symbol ExprSelect::evalExceptFinalSelect(EvalState & state, Env & env, Value & attrs)
{
Value vTmp;
Symbol name = getName(attrPath[attrPath.size() - 1], state, env);
if (attrPath.size() == 1) {
e->eval(state, env, vTmp);
} else {
ExprSelect init(*this);
init.attrPath.pop_back();
init.eval(state, env, vTmp);
}
attrs = vTmp;
return name;
}
void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
{
@ -2876,13 +2892,37 @@ Expr * EvalState::parse(
const SourcePath & basePath,
std::shared_ptr<StaticEnv> & staticEnv)
{
auto result = parseExprFromBuf(text, length, origin, basePath, symbols, settings, positions, rootFS, exprSymbols);
DocCommentMap tmpDocComments; // Only used when not origin is not a SourcePath
DocCommentMap *docComments = &tmpDocComments;
if (auto sourcePath = std::get_if<SourcePath>(&origin)) {
auto [it, _] = positionToDocComment.try_emplace(*sourcePath);
docComments = &it->second;
}
auto result = parseExprFromBuf(text, length, origin, basePath, symbols, settings, positions, *docComments, rootFS, exprSymbols);
result->bindVars(*this, staticEnv);
return result;
}
DocComment EvalState::getDocCommentForPos(PosIdx pos)
{
auto pos2 = positions[pos];
auto path = pos2.getSourcePath();
if (!path)
return {};
auto table = positionToDocComment.find(*path);
if (table == positionToDocComment.end())
return {};
auto it = table->second.find(pos);
if (it == table->second.end())
return {};
return it->second;
}
std::string ExternalValueBase::coerceToString(EvalState & state, const PosIdx & pos, NixStringContext & context, bool copyMore, bool copyToStore) const
{

View file

@ -130,6 +130,8 @@ struct Constant
typedef std::map<std::string, Value *> ValMap;
#endif
typedef std::map<PosIdx, DocComment> DocCommentMap;
struct Env
{
Env * up;
@ -329,6 +331,12 @@ private:
#endif
FileEvalCache fileEvalCache;
/**
* Associate source positions of certain AST nodes with their preceding doc comment, if they have one.
* Grouped by file.
*/
std::map<SourcePath, DocCommentMap> positionToDocComment;
LookupPath lookupPath;
std::map<std::string, std::optional<std::string>> lookupPathResolved;
@ -771,6 +779,8 @@ public:
std::string_view pathArg,
PosIdx pos);
DocComment getDocCommentForPos(PosIdx pos);
private:
/**

View file

@ -202,6 +202,17 @@ struct ExprSelect : Expr
ExprSelect(const PosIdx & pos, Expr * e, AttrPath attrPath, Expr * def) : pos(pos), e(e), def(def), attrPath(std::move(attrPath)) { };
ExprSelect(const PosIdx & pos, Expr * e, Symbol name) : pos(pos), e(e), def(0) { attrPath.push_back(AttrName(name)); };
PosIdx getPos() const override { return pos; }
/**
* Evaluate the `a.b.c` part of `a.b.c.d`. This exists mostly for the purpose of :doc in the repl.
*
* @param[out] v The attribute set that should contain the last attribute name (if it exists).
* @return The last attribute name in `attrPath`
*
* @note This does *not* evaluate the final attribute, and does not fail if that's the only attribute that does not exist.
*/
Symbol evalExceptFinalSelect(EvalState & state, Env & env, Value & attrs);
COMMON_METHODS
};

View file

@ -64,7 +64,7 @@ struct LexerState
/**
* @brief Maps some positions to a DocComment, where the comment is relevant to the location.
*/
std::map<PosIdx, DocComment> positionToDocComment;
std::map<PosIdx, DocComment> & positionToDocComment;
PosTable & positions;
PosTable::Origin origin;

View file

@ -33,6 +33,8 @@
namespace nix {
typedef std::map<PosIdx, DocComment> DocCommentMap;
Expr * parseExprFromBuf(
char * text,
size_t length,
@ -41,6 +43,7 @@ Expr * parseExprFromBuf(
SymbolTable & symbols,
const EvalSettings & settings,
PosTable & positions,
DocCommentMap & docComments,
const ref<SourceAccessor> rootFS,
const Expr::AstSymbols & astSymbols);
@ -335,10 +338,12 @@ binds
$$ = $1;
auto pos = state->at(@2);
auto exprPos = state->at(@4);
{
auto it = state->lexerState.positionToDocComment.find(pos);
if (it != state->lexerState.positionToDocComment.end()) {
$4->setDocComment(it->second);
state->lexerState.positionToDocComment.emplace(exprPos, it->second);
}
}
@ -463,11 +468,13 @@ Expr * parseExprFromBuf(
SymbolTable & symbols,
const EvalSettings & settings,
PosTable & positions,
DocCommentMap & docComments,
const ref<SourceAccessor> rootFS,
const Expr::AstSymbols & astSymbols)
{
yyscan_t scanner;
LexerState lexerState {
.positionToDocComment = docComments,
.positions = positions,
.origin = positions.addOrigin(origin, length),
};