3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-07-29 15:37:59 +00:00

WIP docs: Proto log_help

Define `PrettyHelp` class with methods for declaring different parts of help message.
Currently able to produce standard help messages as expected.
Updates chformal to use (only) the new help_v2.
Currently makes use of a global static to track the current help context, allowing register.h to live in blissful ignorance and instead rely on help_v2 implementations calling `auto *help = PrettyHelp::get_current();` and `return true;` to minimise impact on rebuilds (i.e. not requiring every source file to be recompiled).
This commit is contained in:
Krystine Sherwin 2025-07-21 10:34:11 +12:00
parent 3718f916f3
commit 3bef122a3f
No known key found for this signature in database
6 changed files with 242 additions and 176 deletions

View file

@ -21,6 +21,7 @@
#include "kernel/satgen.h"
#include "kernel/json.h"
#include "kernel/gzip.h"
#include "kernel/log_help.h"
#include <string.h>
#include <stdlib.h>
@ -41,7 +42,7 @@ std::map<std::string, Backend*> backend_register;
std::vector<std::string> Frontend::next_args;
Pass::Pass(std::string name, std::string short_help, const vector<std::string> doc_string, const vector<PassUsageBlock> usages) : pass_name(name), short_help(short_help), doc_string(doc_string), pass_usages(usages)
Pass::Pass(std::string name, std::string short_help) : pass_name(name), short_help(short_help)
{
next_queued_pass = first_queued_pass;
first_queued_pass = this;
@ -114,79 +115,20 @@ void Pass::post_execute(Pass::pre_post_exec_state_t state)
current_pass->runtime_ns -= time_ns;
}
#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())
return;
std::istringstream iss(pass_str);
if (leading_newline)
log("\n");
for (std::string line; std::getline(iss, line);) {
log("%s", indent_str.c_str());
auto curr_len = indent_str.length();
std::istringstream lss(line);
for (std::string word; std::getline(lss, word, ' ');) {
while (word[0] == '`' && word.back() == '`')
word = word.substr(1, word.length()-2);
if (curr_len + word.length() >= MAX_LINE_LEN-1) {
curr_len = 0;
log("\n%s", indent_str.c_str());
}
if (word.length()) {
log("%s ", word.c_str());
curr_len += word.length() + 1;
}
}
log("\n");
}
}
void log_pass_str(const std::string &pass_str, int indent=0, bool leading_newline=false) {
std::string indent_str(indent*4, ' ');
log_pass_str(pass_str, indent_str, leading_newline);
}
void Pass::help()
{
if (HasUsages()) {
for (auto usage : pass_usages) {
log_pass_str(usage.signature, 1, true);
log_pass_str(usage.description, 0, true);
for (auto option : usage.options) {
log_pass_str(option.keyword, 1, true);
log_pass_str(option.description, 2, false);
}
log_pass_str(usage.postscript, 0, true);
}
log("\n");
} else if (HasDocstring()) {
log("\n");
auto print_empty = true;
for (auto doc_line : doc_string) {
if (doc_line.find("..") == 0 && doc_line.find(":: ") != std::string::npos) {
auto command_pos = doc_line.find(":: ");
auto command_str = doc_line.substr(0, command_pos);
if (command_str.compare(".. cmd:usage") == 0) {
log_pass_str(doc_line.substr(command_pos+3), 1);
} else {
print_empty = false;
}
} else if (doc_line.length()) {
std::size_t first_pos = doc_line.find_first_not_of(" \t");
auto indent_str = doc_line.substr(0, first_pos);
log_pass_str(doc_line, indent_str);
print_empty = true;
} else if (print_empty) {
log("\n");
}
}
log("\n");
} else {
if (!help_v2()) {
log("\n");
log("No help message for command `%s'.\n", pass_name.c_str());
log("\n");
}
}
bool Pass::help_v2()
{
return false;
}
void Pass::clear_flags()
{
}
@ -878,13 +820,12 @@ struct HelpPass : public Pass {
auto name = it.first;
auto pass = it.second;
auto title = pass->short_help;
vector<PassUsageBlock> usages;
auto experimental_flag = pass->experimental_flag;
if (pass->HasUsages() || pass->HasDocstring()) {
for (auto usage : pass->pass_usages)
usages.push_back(usage);
} else {
auto cmd_help = PrettyHelp();
auto has_pretty_help = pass->help_v2();
if (!has_pretty_help) {
enum PassUsageState {
PUState_signature,
PUState_description,
@ -932,7 +873,7 @@ struct HelpPass : public Pass {
if (NewUsage) {
current_state = PUState_signature;
usages.push_back({});
// usages.push_back({});
def_strip_count = first_pos;
catch_verific = false;
} else if (IsDedent) {
@ -945,19 +886,19 @@ struct HelpPass : public Pass {
if (IsDefinition && IsIndent && !catch_verific) {
current_state = PUState_options;
usages.back().options.push_back(PassOption({stripped_line, ""}));
// usages.back().options.push_back(PassOption({stripped_line, ""}));
def_strip_count = first_pos;
} else {
string *desc_str;
if (current_state == PUState_signature) {
desc_str = &(usages.back().signature);
// desc_str = &(usages.back().signature);
blank_count += 1;
} else if (current_state == PUState_description) {
desc_str = &(usages.back().description);
// desc_str = &(usages.back().description);
} else if (current_state == PUState_options) {
desc_str = &(usages.back().options.back().description);
// desc_str = &(usages.back().options.back().description);
} else if (current_state == PUState_postscript) {
desc_str = &(usages.back().postscript);
// desc_str = &(usages.back().postscript);
} else {
log_abort();
}
@ -978,28 +919,7 @@ struct HelpPass : public Pass {
// write to json
json.name(name.c_str()); json.begin_object();
json.entry("title", title);
if (pass->HasDocstring()) {
json.entry("content", pass->doc_string);
}
if (usages.size()) {
json.name("usages"); json.begin_array();
for (auto usage : usages) {
json.begin_object();
json.entry("signature", usage.signature);
json.entry("description", usage.description);
json.name("options"); json.begin_array();
for (auto option : usage.options) {
json.begin_array();
json.value(option.keyword);
json.value(option.description);
json.end_array();
}
json.end_array();
json.entry("postscript", usage.postscript);
json.end_object();
}
json.end_array();
}
// json.entry("content", cmd_help);
json.entry("experimental_flag", experimental_flag);
json.end_object();
}