Mercurial > irccd
diff irccdctl/cli.cpp @ 804:d55a64c6586b
irccdctl: unify CLI output, closes #928 @1h
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 14 Nov 2018 14:07:05 +0100 |
parents | f26bb089232d |
children | 5a421b20a4f4 |
line wrap: on
line diff
--- a/irccdctl/cli.cpp Tue Nov 13 20:21:18 2018 +0100 +++ b/irccdctl/cli.cpp Wed Nov 14 14:07:05 2018 +0100 @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <iomanip> +#include <ios> #include <iostream> #include <irccd/json_util.hpp> @@ -29,6 +31,7 @@ #include "cli.hpp" using irccd::json_util::deserializer; +using irccd::json_util::pretty; namespace irccd::ctl { @@ -37,6 +40,15 @@ namespace { template <typename T> +auto operator<<(std::ostream& out, const std::optional<T>& value) -> std::ostream& +{ + if (value) + out << pretty(*value); + + return out; +} + +template <typename T> auto bind() noexcept -> cli::constructor { return [] () noexcept { @@ -59,114 +71,121 @@ return "native"; } -void onConnect(const nlohmann::json &v) +auto align(std::string_view topic) -> std::ostream& { - std::cout << "event: onConnect\n"; - std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; + assert(topic.size() <= 16); + + return std::cout << std::setw(16) << std::left << topic; } -void onInvite(const nlohmann::json &v) +void onConnect(const deserializer& v) { - std::cout << "event: onInvite\n"; - std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; - std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; - std::cout << "channel: " << json_util::pretty(v.value("channel", "(unknown)")) << "\n"; + align("event:") << "onConnect\n"; + align("server:") << v.get<std::string>("server") << "\n"; } -void onJoin(const nlohmann::json &v) +void onInvite(const deserializer& v) { - std::cout << "event: onJoin\n"; - std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; - std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; - std::cout << "channel: " << json_util::pretty(v.value("channel", "(unknown)")) << "\n"; + align("event:") << "onInvite\n"; + align("server:") << v.get<std::string>("server") << "\n"; + align("origin:") << v.get<std::string>("origin") << "\n"; + align("channel:") << v.get<std::string>("channel") << "\n"; } -void onKick(const nlohmann::json &v) +void onJoin(const deserializer& v) { - std::cout << "event: onKick\n"; - std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; - std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; - std::cout << "channel: " << json_util::pretty(v.value("channel", "(unknown)")) << "\n"; - std::cout << "target: " << json_util::pretty(v.value("target", "(unknown)")) << "\n"; - std::cout << "reason: " << json_util::pretty(v.value("reason", "(unknown)")) << "\n"; + align("event:") << "onJoin\n"; + align("server:") << v.get<std::string>("server") << "\n"; + align("origin:") << v.get<std::string>("origin") << "\n"; + align("channel:") << v.get<std::string>("channel") << "\n"; } -void onMessage(const nlohmann::json &v) +void onKick(const deserializer& v) { - std::cout << "event: onMessage\n"; - std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; - std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; - std::cout << "channel: " << json_util::pretty(v.value("channel", "(unknown)")) << "\n"; - std::cout << "message: " << json_util::pretty(v.value("message", "(unknown)")) << "\n"; + align("event:") << "onKick\n"; + align("server:") << v.get<std::string>("server") << "\n"; + align("origin:") << v.get<std::string>("origin") << "\n"; + align("channel:") << v.get<std::string>("channel") << "\n"; + align("target:") << v.get<std::string>("target") << "\n"; + align("reason:") << v.get<std::string>("reason") << "\n"; } -void onMe(const nlohmann::json &v) +void onMessage(const deserializer& v) { - std::cout << "event: onMe\n"; - std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; - std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; - std::cout << "target: " << json_util::pretty(v.value("target", "(unknown)")) << "\n"; - std::cout << "message: " << json_util::pretty(v.value("message", "(unknown)")) << "\n"; + align("event:") << "onMessage\n"; + align("server:") << v.get<std::string>("server") << "\n"; + align("origin:") << v.get<std::string>("origin") << "\n"; + align("channel:") << v.get<std::string>("channel") << "\n"; + align("message:") << v.get<std::string>("message") << "\n"; +} + +void onMe(const deserializer& v) +{ + align("event:") << "onMe\n"; + align("server:") << v.get<std::string>("server") << "\n"; + align("origin:") << v.get<std::string>("origin") << "\n"; + align("target:") << v.get<std::string>("target") << "\n"; + align("message:") << v.get<std::string>("message") << "\n"; } -void onMode(const nlohmann::json &v) +void onMode(const deserializer& v) { - std::cout << "event: onMode\n"; - std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; - std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; - std::cout << "mode: " << json_util::pretty(v.value("mode", "(unknown)")) << "\n"; + align("event:") << "onMode\n"; + align("server:") << v.get<std::string>("server") << "\n"; + align("origin:") << v.get<std::string>("origin") << "\n"; + align("mode:") << v.get<std::string>("mode") << "\n"; } -void onNames(const nlohmann::json &v) +void onNames(const deserializer& v) { - std::cout << "event: onNames\n"; - std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; - std::cout << "channel: " << json_util::pretty(v.value("channel", "(unknown)")) << "\n"; - std::cout << "names: " << json_util::pretty(v.value("names", "(unknown)")) << "\n"; + align("event:") << "onNames\n"; + align("server:") << v.get<std::string>("server") << "\n"; + align("channel:") << v.get<std::string>("channel") << "\n"; + align("names:") << v.get<std::string>("names") << "\n"; } -void onNick(const nlohmann::json &v) +void onNick(const deserializer& v) { - std::cout << "event: onNick\n"; - std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; - std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; - std::cout << "nickname: " << json_util::pretty(v.value("nickname", "(unknown)")) << "\n"; + align("event:") << "onNick\n"; + align("server:") << v.get<std::string>("server") << "\n"; + align("origin:") << v.get<std::string>("origin") << "\n"; + align("nickname:") << v.get<std::string>("nickname") << "\n"; } -void onNotice(const nlohmann::json &v) +void onNotice(const deserializer& v) { - std::cout << "event: onNotice\n"; - std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; - std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; - std::cout << "message: " << json_util::pretty(v.value("message", "(unknown)")) << "\n"; + align("event:") << "onNotice\n"; + align("server:") << v.get<std::string>("server") << "\n"; + align("origin:") << v.get<std::string>("origin") << "\n"; + align("message:") << v.get<std::string>("message") << "\n"; } -void onPart(const nlohmann::json &v) +void onPart(const deserializer& v) { - std::cout << "event: onPart\n"; - std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; - std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; - std::cout << "channel: " << json_util::pretty(v.value("channel", "(unknown)")) << "\n"; - std::cout << "reason: " << json_util::pretty(v.value("reason", "(unknown)")) << "\n"; + align("event:") << "onPart\n"; + align("server:") << v.get<std::string>("server") << "\n"; + align("origin:") << v.get<std::string>("origin") << "\n"; + align("channel:") << v.get<std::string>("channel") << "\n"; + align("reason:") << v.get<std::string>("reason") << "\n"; } -void onTopic(const nlohmann::json &v) +void onTopic(const deserializer& v) { - std::cout << "event: onTopic\n"; - std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; - std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; - std::cout << "channel: " << json_util::pretty(v.value("channel", "(unknown)")) << "\n"; - std::cout << "topic: " << json_util::pretty(v.value("topic", "(unknown)")) << "\n"; + align("event:") << "onTopic\n"; + align("server:") << v.get<std::string>("server") << "\n"; + align("origin:") << v.get<std::string>("origin") << "\n"; + align("channel:") << v.get<std::string>("channel") << "\n"; + align("topic:") << v.get<std::string>("topic") << "\n"; } -void onWhois(const nlohmann::json &v) +void onWhois(const deserializer& v) { - std::cout << "event: onWhois\n"; - std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; - std::cout << "nickname: " << json_util::pretty(v.value("nickname", "(unknown)")) << "\n"; - std::cout << "username: " << json_util::pretty(v.value("username", "(unknown)")) << "\n"; - std::cout << "hostname: " << json_util::pretty(v.value("hostname", "(unknown)")) << "\n"; - std::cout << "realname: " << json_util::pretty(v.value("realname", "(unknown)")) << "\n"; + align("event:") << "onWhois\n"; + align("server:") << v.get<std::string>("server") << "\n"; + align("nickname:") << v.get<std::string>("nickname") << "\n"; + align("username:") << v.get<std::string>("username") << "\n"; + align("hostname:") << v.get<std::string>("hostname") << "\n"; + align("realname:") << v.get<std::string>("realname") << "\n"; } const std::unordered_map<std::string_view, std::function<void (const nlohmann::json&)>> events{ @@ -188,17 +207,19 @@ void get_event(ctl::controller& ctl, std::string fmt) { ctl.recv([&ctl, fmt] (auto code, auto message) { + const deserializer doc(message); + if (code) throw std::system_error(code); - const auto event = deserializer(message).get<std::string>("event"); + const auto event = doc.get<std::string>("event"); const auto it = events.find(event ? *event : ""); if (it != events.end()) { if (fmt == "json") std::cout << message.dump(4) << std::endl; else { - it->second(message); + it->second(doc); std::cout << std::endl; } } @@ -315,7 +336,7 @@ request(ctl, std::move(json), [args] (auto result) { if (result["variables"].is_object()) - std::cout << json_util::pretty(result["variables"][args[1]]) << std::endl; + std::cout << pretty(result["variables"][args[1]]) << std::endl; }); } @@ -330,7 +351,7 @@ const auto variables = result["variables"]; for (auto v = variables.begin(); v != variables.end(); ++v) - std::cout << std::setw(16) << std::left << v.key() << " : " << json_util::pretty(v.value()) << std::endl; + std::cout << std::setw(16) << std::left << v.key() << " : " << pretty(v.value()) << std::endl; }); } @@ -378,15 +399,10 @@ request(ctl, json, [] (auto result) { const deserializer doc(result); - std::cout << std::boolalpha; - std::cout << "Author : " - << doc.get<std::string>("author").value_or("(unknown)") << std::endl; - std::cout << "License : " - << doc.get<std::string>("license").value_or("(unknown)") << std::endl; - std::cout << "Summary : " - << doc.get<std::string>("summary").value_or("(unknown)") << std::endl; - std::cout << "Version : " - << doc.get<std::string>("version").value_or("(unknown)") << std::endl; + align("author:") << doc.get<std::string>("author") << std::endl; + align("license:") << doc.get<std::string>("license") << std::endl; + align("summary:") << doc.get<std::string>("summary") << std::endl; + align("version:") << doc.get<std::string>("version") << std::endl; }); } @@ -644,13 +660,12 @@ return "drop"; }; - std::cout << "rule: " << index << std::endl; - std::cout << "servers: " << unjoin(json["servers"]) << std::endl; - std::cout << "channels: " << unjoin(json["channels"]) << std::endl; - std::cout << "plugins: " << unjoin(json["plugins"]) << std::endl; - std::cout << "events: " << unjoin(json["events"]) << std::endl; - std::cout << "action: " << unstr(json["action"]) << std::endl; - std::cout << std::endl; + align("rule:") << index << std::endl; + align("servers:") << unjoin(json["servers"]) << std::endl; + align("channels:") << unjoin(json["channels"]) << std::endl; + align("plugins:") << unjoin(json["plugins"]) << std::endl; + align("events:") << unjoin(json["events"]) << std::endl; + align("action:") << unstr(json["action"]) << std::endl; } auto rule_info_cli::get_name() const noexcept -> std::string_view @@ -691,10 +706,17 @@ { request(ctl, {{ "command", "rule-list" }}, [] (auto result) { auto pos = 0; + auto length = result["list"].size(); - for (const auto& obj : result["list"]) - if (obj.is_object()) - rule_info_cli::print(obj, pos++); + for (const auto& obj : result["list"]) { + if (!obj.is_object()) + continue; + + rule_info_cli::print(obj, pos++); + + if (pos < length) + std::cout << std::endl; + } }); } @@ -847,24 +869,24 @@ }); request(ctl, std::move(json), [] (auto result) { - std::cout << std::boolalpha; - std::cout << "Name : " << json_util::pretty(result["name"]) << std::endl; - std::cout << "Hostname : " << json_util::pretty(result["hostname"]) << std::endl; - std::cout << "Port : " << json_util::pretty(result["port"]) << std::endl; - std::cout << "Ipv6 : " << json_util::pretty(result["ipv6"]) << std::endl; - std::cout << "SSL : " << json_util::pretty(result["ssl"]) << std::endl; - std::cout << "SSL verified : " << json_util::pretty(result["sslVerify"]) << std::endl; - std::cout << "Channels : "; + const deserializer doc(result); + + align("name:") << doc.get<std::string>("name") << std::endl; + align("hostname:") << doc.get<std::string>("hostname") << std::endl; + align("port:") << doc.get<std::uint64_t>("port") << std::endl; + align("nickname:") << doc.get<std::string>("nickname") << std::endl; + align("username:") << doc.get<std::string>("username") << std::endl; + align("realname:") << doc.get<std::string>("realname") << std::endl; + align("ipv4:") << doc.get<bool>("ipv4") << std::endl; + align("ipv6:") << doc.get<bool>("ipv6") << std::endl; + align("ssl:") << doc.get<bool>("ssl") << std::endl; + align("channels:"); for (const auto& v : result["channels"]) if (v.is_string()) std::cout << v.template get<std::string>() << " "; std::cout << std::endl; - - std::cout << "Nickname : " << json_util::pretty(result["nickname"]) << std::endl; - std::cout << "User name : " << json_util::pretty(result["username"]) << std::endl; - std::cout << "Real name : " << json_util::pretty(result["realname"]) << std::endl; }); }