mirror of https://github.com/YosysHQ/yosys.git
log_help: Json dumpable
Current modes are `LOG` and `LISTING`, which `log()` and store for conversion to json respectively. Add `ContentListing` listing struct to (recursively) contain help data for conversion to a json object to be exported and used elsewhere (e.g. the docs). Rather than formatting as rst we can just export with type information and do the conversion at the destination (i.e. in the python code which loads the domain for autodoc). Implement `PrettyHelp::has_content()`. Provide `PrettyHelp::get_content()` which returns a read-only list of the current content. `PrettyHelp` constructor takes optional `Mode` enum to define format of help content. Updates `PrettyHelp` methods to use a switch case for checking current mode, calling `log_abort()` in the default case (i.e. unsupported mode).
This commit is contained in:
parent
36e5d4c3d5
commit
40d22adb36
|
@ -21,6 +21,18 @@
|
|||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
Json ContentListing::to_json() {
|
||||
Json::object object;
|
||||
object["type"] = type;
|
||||
if (body.length()) object["body"] = body;
|
||||
if (source_file != nullptr) object["source_file"] = source_file;
|
||||
if (source_line != 0) object["source_line"] = source_line;
|
||||
Json::array content_array;
|
||||
for (auto child : content) content_array.push_back(child->to_json());
|
||||
object["content"] = content_array;
|
||||
return object;
|
||||
}
|
||||
|
||||
#define MAX_LINE_LEN 80
|
||||
void log_pass_str(const std::string &pass_str, std::string indent_str, bool leading_newline=false) {
|
||||
if (pass_str.empty())
|
||||
|
@ -54,15 +66,22 @@ void log_pass_str(const std::string &pass_str, int indent=0, bool leading_newlin
|
|||
|
||||
PrettyHelp *current_help = nullptr;
|
||||
|
||||
PrettyHelp::PrettyHelp()
|
||||
PrettyHelp::PrettyHelp(Mode mode)
|
||||
{
|
||||
prior = current_help;
|
||||
_prior = current_help;
|
||||
_mode = mode;
|
||||
_root_listing = ContentListing({
|
||||
.type = "root"
|
||||
});
|
||||
_root_listing.type = "root";
|
||||
_current_listing = &_root_listing;
|
||||
|
||||
current_help = this;
|
||||
}
|
||||
|
||||
PrettyHelp::~PrettyHelp()
|
||||
{
|
||||
current_help = prior;
|
||||
current_help = _prior;
|
||||
}
|
||||
|
||||
PrettyHelp *PrettyHelp::get_current()
|
||||
|
@ -73,16 +92,21 @@ PrettyHelp *PrettyHelp::get_current()
|
|||
return new PrettyHelp();
|
||||
}
|
||||
|
||||
bool PrettyHelp::has_content()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void PrettyHelp::usage(const string &usage,
|
||||
const source_location location)
|
||||
{
|
||||
log_pass_str(usage, current_indent+1, true);
|
||||
log("\n");
|
||||
switch (_mode)
|
||||
{
|
||||
case LOG:
|
||||
log_pass_str(usage, _current_indent+1, true);
|
||||
log("\n");
|
||||
break;
|
||||
case LISTING:
|
||||
_current_listing->add_content("usage", usage, location);
|
||||
break;
|
||||
default:
|
||||
log_abort();
|
||||
}
|
||||
}
|
||||
|
||||
void PrettyHelp::option(const string &text, const string &description,
|
||||
|
@ -90,40 +114,108 @@ void PrettyHelp::option(const string &text, const string &description,
|
|||
{
|
||||
open_option(text);
|
||||
if (description.length()) {
|
||||
log_pass_str(description, current_indent);
|
||||
log("\n");
|
||||
switch (_mode)
|
||||
{
|
||||
case LOG:
|
||||
log_pass_str(description, _current_indent);
|
||||
log("\n");
|
||||
break;
|
||||
case LISTING:
|
||||
_current_listing->add_content("text", description, location);
|
||||
break;
|
||||
default:
|
||||
log_abort();
|
||||
}
|
||||
}
|
||||
close(1);
|
||||
}
|
||||
|
||||
void PrettyHelp::codeblock(const string &code, const string &,
|
||||
void PrettyHelp::codeblock(const string &code, const string &language,
|
||||
const source_location location)
|
||||
{
|
||||
log("%s\n", code.c_str());
|
||||
switch (_mode)
|
||||
{
|
||||
case LOG:
|
||||
log("%s\n", code.c_str());
|
||||
break;
|
||||
case LISTING:
|
||||
_current_listing->add_content("code", code, location);
|
||||
break;
|
||||
default:
|
||||
log_abort();
|
||||
}
|
||||
}
|
||||
|
||||
void PrettyHelp::paragraph(const string &text,
|
||||
const source_location location)
|
||||
{
|
||||
log_pass_str(text, current_indent);
|
||||
log("\n");
|
||||
switch (_mode)
|
||||
{
|
||||
case LOG:
|
||||
log_pass_str(text, _current_indent);
|
||||
log("\n");
|
||||
break;
|
||||
case LISTING:
|
||||
_current_listing->add_content("text", text, location);
|
||||
break;
|
||||
default:
|
||||
log_abort();
|
||||
}
|
||||
}
|
||||
|
||||
void PrettyHelp::open_optiongroup(const string &,
|
||||
void PrettyHelp::open_optiongroup(const string &name,
|
||||
const source_location location)
|
||||
{
|
||||
current_indent += 1;
|
||||
switch (_mode)
|
||||
{
|
||||
case LOG:
|
||||
break;
|
||||
case LISTING:
|
||||
_current_listing->add_content("optiongroup", name, location);
|
||||
_current_listing = _current_listing->content.back();
|
||||
break;
|
||||
default:
|
||||
log_abort();
|
||||
}
|
||||
_current_indent += 1;
|
||||
}
|
||||
|
||||
void PrettyHelp::open_option(const string &text,
|
||||
const source_location location)
|
||||
{
|
||||
log_pass_str(text, current_indent);
|
||||
current_indent += 1;
|
||||
switch (_mode)
|
||||
{
|
||||
case LOG:
|
||||
log_pass_str(text, _current_indent);
|
||||
break;
|
||||
case LISTING:
|
||||
_current_listing->add_content("option", text, location);
|
||||
_current_listing = _current_listing->content.back();
|
||||
break;
|
||||
default:
|
||||
log_abort();
|
||||
}
|
||||
_current_indent += 1;
|
||||
}
|
||||
|
||||
void PrettyHelp::close(int levels)
|
||||
{
|
||||
current_indent -= levels;
|
||||
log_assert(current_indent >= 0);
|
||||
|
||||
switch (_mode)
|
||||
{
|
||||
case LOG:
|
||||
_current_indent -= levels;
|
||||
log_assert(_current_indent >= 0);
|
||||
break;
|
||||
case LISTING:
|
||||
for (int i=0; i<levels; i++) {
|
||||
_current_indent--;
|
||||
log_assert(_current_indent >= 0);
|
||||
_current_listing = _current_listing->parent;
|
||||
log_assert(_current_listing != nullptr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_abort();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,17 +38,57 @@ struct source_location { // dummy placeholder
|
|||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
struct ContentListing {
|
||||
string type = "root";
|
||||
string body = "";
|
||||
const char* source_file = nullptr;
|
||||
int source_line = 0;
|
||||
vector<ContentListing *> content = {};
|
||||
ContentListing *parent = nullptr;
|
||||
|
||||
void add_content(ContentListing *new_content) {
|
||||
new_content->parent = this;
|
||||
content.push_back(new_content);
|
||||
}
|
||||
|
||||
void add_content(string type, string body, source_location location) {
|
||||
auto new_content = new ContentListing();
|
||||
new_content->type = type;
|
||||
new_content->body = body;
|
||||
new_content->source_file = location.file_name();
|
||||
new_content->source_line = location.line();
|
||||
add_content(new_content);
|
||||
}
|
||||
|
||||
Json to_json();
|
||||
};
|
||||
|
||||
class PrettyHelp
|
||||
{
|
||||
PrettyHelp *prior = nullptr;
|
||||
int current_indent = 0;
|
||||
public:
|
||||
PrettyHelp();
|
||||
enum Mode {
|
||||
LOG,
|
||||
LISTING,
|
||||
};
|
||||
|
||||
private:
|
||||
PrettyHelp *_prior;
|
||||
Mode _mode;
|
||||
|
||||
int _current_indent = 0;
|
||||
ContentListing _root_listing;
|
||||
ContentListing *_current_listing;
|
||||
public:
|
||||
PrettyHelp(Mode mode = LOG);
|
||||
~PrettyHelp();
|
||||
|
||||
static PrettyHelp *get_current();
|
||||
|
||||
bool has_content();
|
||||
bool has_content() { return _root_listing.content.size();}
|
||||
const vector<ContentListing *> get_content() {
|
||||
const vector<ContentListing *> content = _root_listing.content;
|
||||
return content;
|
||||
}
|
||||
|
||||
void usage(
|
||||
const string &usage,
|
||||
|
@ -70,7 +110,7 @@ public:
|
|||
);
|
||||
|
||||
void open_optiongroup(
|
||||
const string &group = "",
|
||||
const string &name = "",
|
||||
const source_location location = source_location::current()
|
||||
);
|
||||
void open_option(
|
||||
|
|
|
@ -919,7 +919,7 @@ struct HelpPass : public Pass {
|
|||
auto title = pass->short_help;
|
||||
auto experimental_flag = pass->experimental_flag;
|
||||
|
||||
auto cmd_help = PrettyHelp();
|
||||
auto cmd_help = PrettyHelp(PrettyHelp::Mode::LISTING);
|
||||
auto has_pretty_help = pass->help_v2();
|
||||
|
||||
if (!has_pretty_help) {
|
||||
|
@ -1016,7 +1016,10 @@ struct HelpPass : public Pass {
|
|||
// write to json
|
||||
json.name(name.c_str()); json.begin_object();
|
||||
json.entry("title", title);
|
||||
// json.entry("content", cmd_help);
|
||||
json.name("content"); json.begin_array();
|
||||
for (auto content : cmd_help.get_content())
|
||||
json.value(content->to_json());
|
||||
json.end_array();
|
||||
json.entry("experimental_flag", experimental_flag);
|
||||
json.end_object();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue