Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.2] Enable new CLI11 LeapFormatter for both cleos and leap-util #399

Merged
merged 3 commits into from
Oct 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 146 additions & 16 deletions libraries/cli11/include/cli11/CLI11.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// https://github.com/CLIUtils/CLI11
//
// This is a standalone header file generated by MakeSingleHeader.py in CLI11/scripts
// from: 1d3b0a7
// from: b19d133
//
// CLI11 2.2.0 Copyright (c) 2017-2022 University of Cincinnati, developed by Henry
// Schreiner under NSF AWARD 1414736. All rights reserved.
Expand Down Expand Up @@ -34,28 +34,28 @@
#pragma once

// Standard combined includes:
#include <string>
#include <memory>
#include <utility>
#include <functional>
#include <iostream>
#include <sstream>
#include <iterator>
#include <type_traits>
#include <vector>
#include <memory>
#include <string>
#include <exception>
#include <cstdint>
#include <cmath>
#include <map>
#include <limits>
#include <numeric>
#include <type_traits>
#include <fstream>
#include <functional>
#include <cstdint>
#include <vector>
#include <tuple>
#include <locale>
#include <algorithm>
#include <stdexcept>
#include <cmath>
#include <set>
#include <stdexcept>
#include <iomanip>
#include <locale>
#include <limits>
#include <sstream>
#include <fstream>
#include <map>
#include <iostream>
#include <utility>


#define CLI11_VERSION_MAJOR 2
Expand Down Expand Up @@ -9420,4 +9420,134 @@ inline std::string Formatter::make_option_usage(const Option *opt) const {




class LeapFormatter : public Formatter {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be pulled out into a separate header for easier integration in the future? Seems like it could be done without having to modify CLI11.hpp at all. Just have cleos and leap-util include it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is autogenerated header during build process of our custom CLI11, which includes other features such as autocomplete/etc, not available in vanilla cli11. It is a separate header in https://github.com/AntelopeIO/CLI11 and is merged into this superheader on build. This header can be moved to leap repo for sure, if you think this would look better, I'll do that (and roll back / close PR in CLI11 with inclusion of this header in build and one more PR there to remove LeapFormatter from repo)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore my comment then. I have not been paying that close attention to this. I'll let @linh2931 review since he has been tracking these changes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does that happen? I cloned AntelopeIO/CLI11@bd54546 and the followed the instructions to build it, i.e I did

git checkout bd545461aaca877b07867156037838abc18ad8dc
mkdir build
cd build/
cmake -DCLI11_SINGLE_FILE=ON ..
make -j

But then

grep Leap include/CLI11.hpp

has nothing. (it doesn't generate the same file as CLI11.hpp here in this PR)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh no, clash of merges out of sync, should be b19d133 one sec, I'll update

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 yes now i'm getting something very close to what is in the PR

// pseudographics - to draw subcommand tree
const char* tree_line = u8"\u2502";
const char* tree_angle = u8"\u2514";
const char* tree_fork = u8"\u251C";

public:
LeapFormatter() : Formatter() {
// this gives better, more compact display
column_width(25);
}
LeapFormatter(const LeapFormatter&) = default;
LeapFormatter(LeapFormatter&&) = default;

/// This prints out all the subcommands
virtual std::string make_subcommands(const App* app, AppFormatMode mode) const {
std::stringstream out;

std::vector<const App*> subcommands = app->get_subcommands({});

// Make a list in definition order of the groups seen
std::vector<std::string> subcmd_groups_seen;
for(const App* com: subcommands) {
if(com->get_name().empty()) {
if(!com->get_group().empty()) {
out << make_expanded(com);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this if the name is empty?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to handle "option groups" in CLI11 (in many places there). Not the cleanest way to do it, but I believe due to evolutionary reasons...

}
continue;
}
std::string group_key = com->get_group();
if(!group_key.empty() &&
std::find_if(subcmd_groups_seen.begin(), subcmd_groups_seen.end(), [&group_key](std::string a) {
linh2931 marked this conversation as resolved.
Show resolved Hide resolved
return detail::to_lower(a) == detail::to_lower(group_key);
}) == subcmd_groups_seen.end())
subcmd_groups_seen.push_back(group_key);
}

// For each group, filter out and print subcommands
for(const std::string& group: subcmd_groups_seen) {
if(mode != AppFormatMode::SubCompact) {// do not show "Subcommands" header for nested tems in compact mode
out << "\n"
<< group << ":\n";
}
std::vector<const App*> subcommands_group = app->get_subcommands([&group](const App* sub_app) {
return detail::to_lower(sub_app->get_group()) == detail::to_lower(group);
});
for(const App* new_com: subcommands_group) {
if(new_com->get_name().empty())
continue;

std::string tree_symbol = (subcommands_group.back() == new_com ? tree_angle : tree_fork);
std::string line_symbol = (subcommands_group.back() == new_com ? "" : tree_line);
std::string subc_symbol = "";

const App* parent = app->get_parent();
if(parent != nullptr) {
std::vector<const App*> sc_group = parent->get_subcommands([&group](const App* sub_app) {
return detail::to_lower(sub_app->get_group()) == detail::to_lower(group);
});
if(sc_group.back() != app) {
subc_symbol = tree_line;
}
}

switch(mode) {
case AppFormatMode::All:
out << tree_symbol << new_com->help(new_com->get_name(), AppFormatMode::Sub);
out << "\n";
break;
case AppFormatMode::AllCompact:

out << tree_symbol << new_com->help(new_com->get_name(), AppFormatMode::SubCompact);
out << line_symbol;
out << "\n";
break;
case AppFormatMode::Normal:
case AppFormatMode::Sub:
out << make_subcommand(new_com);
break;
case AppFormatMode::SubCompact:
out << tree_symbol << make_expanded(new_com, mode);
break;
default:
throw HorribleError("Internal error: unknown help type requested");
}
}
}

return out.str();
}

/// This prints out a subcommand in help-all
virtual std::string make_expanded(const App* sub, AppFormatMode mode = AppFormatMode::Sub) const {
std::stringstream out;
std::string tmp;
std::string subc_symbol = " ";
if(mode == AppFormatMode::SubCompact) {
detail::format_help(out, sub->get_display_name(true), sub->get_description(), column_width_);
out << make_subcommands(sub, mode);
} else {
out << sub->get_display_name(true) << "\n";
out << make_description(sub);
if(sub->get_name().empty() && !sub->get_aliases().empty()) {
detail::format_aliases(out, sub->get_aliases(), column_width_ + 2);
}
out << make_positionals(sub);
out << make_groups(sub, mode);
out << make_subcommands(sub, mode);
}

// Drop blank spaces
tmp = detail::find_and_replace(out.str(), "\n\n", "\n");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not mach the comment above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will update these comments in CLI11 lib as well to "Drop blank lines", this header is autogenerated

tmp = tmp.substr(0, tmp.size() - 1);// Remove the final '\n'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure the end of the string is always '\n'?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes in this context. Thank you!


//
auto group = sub->get_parent()->get_group();
std::vector<const App*> sc_group = sub->get_parent()->get_subcommands(
[&group](const App* sub_app) { return detail::to_lower(sub_app->get_group()) == detail::to_lower(group); });

if(sc_group.back() != sub) {
subc_symbol = tree_line;
}

// Indent all but the first line (the name)
return detail::find_and_replace(tmp, "\n", "\n" + subc_symbol + " ") + "\n";
}
};


} // namespace CLI
7 changes: 7 additions & 0 deletions programs/cleos/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2759,9 +2759,16 @@ int main( int argc, char** argv ) {
wallet_url = default_wallet_url;

CLI::App app{"Command Line Interface to EOSIO Client"};

// custom leap formatter
auto fmt = std::make_shared<CLI::LeapFormatter>();
app.formatter(fmt);

// enable help-all, display help on error
app.set_help_all_flag("--help-all", "Show all help");
app.failure_message(CLI::FailureMessage::help);
app.require_subcommand();

// Hide obsolete options by putting them into a group with an empty name.
app.add_option( "-H,--host", obsoleted_option_host_port, localized("The host where ${n} is running", ("n", node_executable_name)) )->group("");
app.add_option( "-p,--port", obsoleted_option_host_port, localized("The port where ${n} is running", ("n", node_executable_name)) )->group("");
Expand Down
4 changes: 2 additions & 2 deletions programs/leap-util/actions/chain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ void chain_actions::setup(CLI::App& app) {
sub->require_subcommand(1);

auto* build = sub->add_subcommand("build-info", "extract build environment information as JSON");
auto opt1 = build->add_option("--output-file,-o", opt->build_output_file, "write into specified file")->capture_default_str();
auto opt2 = build->add_flag("--print,-p", opt->build_just_print, "print to console");
build->add_option("--output-file,-o", opt->build_output_file, "write into specified file")->capture_default_str();
build->add_flag("--print,-p", opt->build_just_print, "print to console");
build->require_option(1);

build->callback([&]() {
Expand Down
12 changes: 0 additions & 12 deletions programs/leap-util/leap_formatter.hpp

This file was deleted.

4 changes: 1 addition & 3 deletions programs/leap-util/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,13 @@

#include <memory>

#include "leap_formatter.hpp"

int main(int argc, char** argv) {
fc::logger::get(DEFAULT_LOGGER).set_log_level(fc::log_level::debug);

CLI::App app{"Leap Command Line Utility"};

// custom leap formatter
auto fmt = std::make_shared<leap_formatter>();
auto fmt = std::make_shared<CLI::LeapFormatter>();
app.formatter(fmt);

app.set_help_all_flag("--help-all", "Show all help");
Expand Down