Allow 'nix' subcommands to provide docs in Markdown format
This commit is contained in:
parent
3c4f8c9175
commit
dc2f278c95
8 changed files with 68 additions and 40 deletions
|
@ -12,7 +12,7 @@ def show_flags:
|
|||
;
|
||||
|
||||
def show_synopsis:
|
||||
"`" + .command + "` " + (.args | map("*" + .label + "*" + (if has("arity") then "" else "..." end)) | join(" ")) + "\n\n"
|
||||
"`" + .command + "` [*flags*...] " + (.args | map("*" + .label + "*" + (if has("arity") then "" else "..." end)) | join(" ")) + "\n\n"
|
||||
;
|
||||
|
||||
def show_command:
|
||||
|
@ -21,6 +21,10 @@ def show_command:
|
|||
+ "`" + .command + "` - " + .def.description + "\n\n"
|
||||
+ .section + " Synopsis\n\n"
|
||||
+ ({"command": .command, "args": .def.args} | show_synopsis)
|
||||
+ (if .def | has("doc")
|
||||
then .section + " Description\n\n" + .def.doc + "\n\n"
|
||||
else ""
|
||||
end)
|
||||
+ (if (.def.flags | length) > 0 then
|
||||
.section + " Flags\n\n"
|
||||
+ (.def | show_flags)
|
||||
|
|
|
@ -359,12 +359,14 @@ nlohmann::json Command::toJSON()
|
|||
for (auto & example : examples()) {
|
||||
auto ex = nlohmann::json::object();
|
||||
ex["description"] = example.description;
|
||||
ex["command"] = example.command;
|
||||
ex["command"] = chomp(stripIndentation(example.command));
|
||||
exs.push_back(std::move(ex));
|
||||
}
|
||||
|
||||
auto res = Args::toJSON();
|
||||
res["examples"] = std::move(exs);
|
||||
auto s = doc();
|
||||
if (s != "") res.emplace("doc", stripIndentation(s));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ public:
|
|||
|
||||
virtual void printHelp(const string & programName, std::ostream & out);
|
||||
|
||||
/* Return a short one-line description of the command. */
|
||||
virtual std::string description() { return ""; }
|
||||
|
||||
protected:
|
||||
|
@ -221,6 +222,9 @@ struct Command : virtual Args
|
|||
virtual void prepare() { };
|
||||
virtual void run() = 0;
|
||||
|
||||
/* Return documentation about this command, in Markdown format. */
|
||||
virtual std::string doc() { return ""; }
|
||||
|
||||
struct Example
|
||||
{
|
||||
std::string description;
|
||||
|
|
|
@ -153,43 +153,6 @@ void Config::convertToArgs(Args & args, const std::string & category)
|
|||
s.second.setting->convertToArg(args, category);
|
||||
}
|
||||
|
||||
static std::string stripIndentation(std::string_view s)
|
||||
{
|
||||
size_t minIndent = 10000;
|
||||
size_t curIndent = 0;
|
||||
bool atStartOfLine = true;
|
||||
|
||||
for (auto & c : s) {
|
||||
if (atStartOfLine && c == ' ')
|
||||
curIndent++;
|
||||
else if (c == '\n') {
|
||||
if (atStartOfLine)
|
||||
minIndent = std::max(minIndent, curIndent);
|
||||
curIndent = 0;
|
||||
atStartOfLine = true;
|
||||
} else {
|
||||
if (atStartOfLine) {
|
||||
minIndent = std::min(minIndent, curIndent);
|
||||
atStartOfLine = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string res;
|
||||
|
||||
size_t pos = 0;
|
||||
while (pos < s.size()) {
|
||||
auto eol = s.find('\n', pos);
|
||||
if (eol == s.npos) eol = s.size();
|
||||
if (eol - pos > minIndent)
|
||||
res.append(s.substr(pos + minIndent, eol - pos - minIndent));
|
||||
res.push_back('\n');
|
||||
pos = eol + 1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
AbstractSetting::AbstractSetting(
|
||||
const std::string & name,
|
||||
const std::string & description,
|
||||
|
|
|
@ -1464,6 +1464,47 @@ string base64Decode(std::string_view s)
|
|||
}
|
||||
|
||||
|
||||
std::string stripIndentation(std::string_view s)
|
||||
{
|
||||
size_t minIndent = 10000;
|
||||
size_t curIndent = 0;
|
||||
bool atStartOfLine = true;
|
||||
|
||||
for (auto & c : s) {
|
||||
if (atStartOfLine && c == ' ')
|
||||
curIndent++;
|
||||
else if (c == '\n') {
|
||||
if (atStartOfLine)
|
||||
minIndent = std::max(minIndent, curIndent);
|
||||
curIndent = 0;
|
||||
atStartOfLine = true;
|
||||
} else {
|
||||
if (atStartOfLine) {
|
||||
minIndent = std::min(minIndent, curIndent);
|
||||
atStartOfLine = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string res;
|
||||
|
||||
size_t pos = 0;
|
||||
while (pos < s.size()) {
|
||||
auto eol = s.find('\n', pos);
|
||||
if (eol == s.npos) eol = s.size();
|
||||
if (eol - pos > minIndent)
|
||||
res.append(s.substr(pos + minIndent, eol - pos - minIndent));
|
||||
res.push_back('\n');
|
||||
pos = eol + 1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
static Sync<std::pair<unsigned short, unsigned short>> windowSize{{0, 0}};
|
||||
|
||||
|
||||
|
|
|
@ -464,6 +464,12 @@ string base64Encode(std::string_view s);
|
|||
string base64Decode(std::string_view s);
|
||||
|
||||
|
||||
/* Remove common leading whitespace from the lines in the string
|
||||
's'. For example, if every line is indented by at least 3 spaces,
|
||||
then we remove 3 spaces from the start of every line. */
|
||||
std::string stripIndentation(std::string_view s);
|
||||
|
||||
|
||||
/* Get a value for the specified key from an associate container. */
|
||||
template <class T>
|
||||
std::optional<typename T::mapped_type> get(const T & map, const typename T::key_type & key)
|
||||
|
|
|
@ -36,6 +36,14 @@ struct CmdAddToStore : MixDryRun, StoreCommand
|
|||
return "add a path to the Nix store";
|
||||
}
|
||||
|
||||
std::string doc() override
|
||||
{
|
||||
return R"(
|
||||
Copy the file or directory *path* to the Nix store, and
|
||||
print the resulting store path on standard output.
|
||||
)";
|
||||
}
|
||||
|
||||
Examples examples() override
|
||||
{
|
||||
return {
|
||||
|
|
|
@ -782,7 +782,7 @@ struct CmdRepl : StoreCommand, MixEvalArgs
|
|||
return {
|
||||
Example{
|
||||
"Display all special commands within the REPL:",
|
||||
"nix repl\n nix-repl> :?"
|
||||
"nix repl\nnix-repl> :?"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue