Allow 'nix' subcommands to provide docs in Markdown format

This commit is contained in:
Eelco Dolstra 2020-08-20 12:21:46 +02:00
parent 3c4f8c9175
commit dc2f278c95
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
8 changed files with 68 additions and 40 deletions

View file

@ -12,7 +12,7 @@ def show_flags:
; ;
def show_synopsis: 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: def show_command:
@ -21,6 +21,10 @@ def show_command:
+ "`" + .command + "` - " + .def.description + "\n\n" + "`" + .command + "` - " + .def.description + "\n\n"
+ .section + " Synopsis\n\n" + .section + " Synopsis\n\n"
+ ({"command": .command, "args": .def.args} | show_synopsis) + ({"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 + (if (.def.flags | length) > 0 then
.section + " Flags\n\n" .section + " Flags\n\n"
+ (.def | show_flags) + (.def | show_flags)

View file

@ -359,12 +359,14 @@ nlohmann::json Command::toJSON()
for (auto & example : examples()) { for (auto & example : examples()) {
auto ex = nlohmann::json::object(); auto ex = nlohmann::json::object();
ex["description"] = example.description; ex["description"] = example.description;
ex["command"] = example.command; ex["command"] = chomp(stripIndentation(example.command));
exs.push_back(std::move(ex)); exs.push_back(std::move(ex));
} }
auto res = Args::toJSON(); auto res = Args::toJSON();
res["examples"] = std::move(exs); res["examples"] = std::move(exs);
auto s = doc();
if (s != "") res.emplace("doc", stripIndentation(s));
return res; return res;
} }

View file

@ -22,6 +22,7 @@ public:
virtual void printHelp(const string & programName, std::ostream & out); virtual void printHelp(const string & programName, std::ostream & out);
/* Return a short one-line description of the command. */
virtual std::string description() { return ""; } virtual std::string description() { return ""; }
protected: protected:
@ -221,6 +222,9 @@ struct Command : virtual Args
virtual void prepare() { }; virtual void prepare() { };
virtual void run() = 0; virtual void run() = 0;
/* Return documentation about this command, in Markdown format. */
virtual std::string doc() { return ""; }
struct Example struct Example
{ {
std::string description; std::string description;

View file

@ -153,43 +153,6 @@ void Config::convertToArgs(Args & args, const std::string & category)
s.second.setting->convertToArg(args, 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( AbstractSetting::AbstractSetting(
const std::string & name, const std::string & name,
const std::string & description, const std::string & description,

View file

@ -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}}; static Sync<std::pair<unsigned short, unsigned short>> windowSize{{0, 0}};

View file

@ -464,6 +464,12 @@ string base64Encode(std::string_view s);
string base64Decode(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. */ /* Get a value for the specified key from an associate container. */
template <class T> template <class T>
std::optional<typename T::mapped_type> get(const T & map, const typename T::key_type & key) std::optional<typename T::mapped_type> get(const T & map, const typename T::key_type & key)

View file

@ -36,6 +36,14 @@ struct CmdAddToStore : MixDryRun, StoreCommand
return "add a path to the Nix store"; 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 Examples examples() override
{ {
return { return {