polybar/src/components/command_line.cpp

181 lines
4.5 KiB
C++
Raw Normal View History

2016-11-25 07:42:31 +00:00
#include <algorithm>
2016-11-02 19:22:45 +00:00
#include <iomanip>
#include <iostream>
2016-11-25 12:55:15 +00:00
#include <utility>
2016-11-02 19:22:45 +00:00
#include "components/command_line.hpp"
2016-11-19 05:22:44 +00:00
POLYBAR_NS
2016-11-02 19:22:45 +00:00
2016-12-09 08:02:47 +00:00
/**
* Create instance
*/
2016-12-09 11:24:01 +00:00
cliparser::make_type cliparser::make(string&& scriptname, const clioptions&& opts) {
return factory_util::unique<cliparser>(
"Usage: " + scriptname + " bar_name [OPTION...]", forward<decltype(opts)>(opts));
2016-12-09 08:02:47 +00:00
}
2016-12-09 11:24:01 +00:00
/**
* Construct parser
*/
cliparser::parser(string&& synopsis, const options&& opts)
: m_synopsis(forward<decltype(synopsis)>(synopsis)), m_opts(forward<decltype(opts)>(opts)) {}
2016-11-02 19:22:45 +00:00
/**
* Print application usage message
*/
void cliparser::usage() const {
2016-12-30 19:57:23 +00:00
std::cout << m_synopsis << "\n\n";
2016-11-02 19:22:45 +00:00
// get the length of the longest string in the flag column
// which is used to align the description fields
size_t maxlen{0};
2016-11-25 12:55:15 +00:00
for (const auto& m_opt : m_opts) {
size_t len{m_opt.flag_long.length() + m_opt.flag.length() + 4};
2016-11-02 19:22:45 +00:00
maxlen = len > maxlen ? len : maxlen;
}
for (auto& opt : m_opts) {
size_t pad = maxlen - opt.flag_long.length() - opt.token.length();
std::cout << " " << opt.flag << ", " << opt.flag_long;
if (!opt.token.empty()) {
std::cout << "=" << opt.token;
pad--;
}
// output the list with accepted values
if (!opt.values.empty()) {
2016-12-30 19:57:23 +00:00
std::cout << std::setw(pad + opt.desc.length()) << std::setfill(' ') << opt.desc << '\n';
2016-11-02 19:22:45 +00:00
pad = pad + opt.flag_long.length() + opt.token.length() + 7;
std::cout << string(pad, ' ') << opt.token << " is one of: ";
for (auto& v : opt.values) {
std::cout << v << (v != opt.values.back() ? ", " : "");
}
} else {
std::cout << std::setw(pad + opt.desc.length()) << std::setfill(' ') << opt.desc;
}
2016-12-30 19:57:23 +00:00
std::cout << '\n';
2016-11-02 19:22:45 +00:00
}
2016-12-30 19:57:23 +00:00
std::cout << std::endl;
2016-11-02 19:22:45 +00:00
}
/**
* Process input values
*/
void cliparser::process_input(const vector<string>& values) {
for (size_t i = 0; i < values.size(); i++) {
parse(values[i], values.size() > i + 1 ? values[i + 1] : "");
}
}
/**
* Test if the passed option was provided
*/
bool cliparser::has(const string& option) const {
return m_optvalues.find(option) != m_optvalues.end();
}
/**
* Gets the value defined for given option
*/
string cliparser::get(string opt) const {
2016-11-25 12:55:15 +00:00
if (has(forward<string>(opt))) {
2016-11-02 19:22:45 +00:00
return m_optvalues.find(opt)->second;
2016-11-25 12:55:15 +00:00
}
2016-11-02 19:22:45 +00:00
return "";
}
/**
* Compare option value with given string
*/
2016-11-25 12:55:15 +00:00
bool cliparser::compare(string opt, const string& val) const {
return get(move(opt)) == val;
2016-11-02 19:22:45 +00:00
}
/**
* Compare option with its short version
*/
2016-11-25 12:55:15 +00:00
auto cliparser::is_short(const string& option, const string& opt_short) const {
2016-11-02 19:22:45 +00:00
return option.compare(0, opt_short.length(), opt_short) == 0;
}
/**
* Compare option with its long version
*/
2016-11-25 12:55:15 +00:00
auto cliparser::is_long(const string& option, const string& opt_long) const {
2016-11-02 19:22:45 +00:00
return option.compare(0, opt_long.length(), opt_long) == 0;
}
/**
* Compare option with both versions
*/
2016-11-25 12:55:15 +00:00
auto cliparser::is(const string& option, string opt_short, string opt_long) const {
return is_short(option, move(opt_short)) || is_long(option, move(opt_long));
2016-11-02 19:22:45 +00:00
}
/**
* Parse option value
*/
2016-11-25 12:55:15 +00:00
auto cliparser::parse_value(string input, const string& input_next, choices values) const {
string opt = move(input);
2016-11-02 19:22:45 +00:00
size_t pos;
string value;
2016-11-25 12:55:15 +00:00
if (input_next.empty() && opt.compare(0, 2, "--") != 0) {
2016-11-02 19:22:45 +00:00
throw value_error("Missing value for " + opt);
2016-11-25 12:55:15 +00:00
} else if ((pos = opt.find('=')) == string::npos && opt.compare(0, 2, "--") == 0) {
2016-11-02 19:22:45 +00:00
throw value_error("Missing value for " + opt);
2016-11-25 12:55:15 +00:00
} else if (pos == string::npos && !input_next.empty()) {
2016-11-02 19:22:45 +00:00
value = input_next;
2016-11-25 12:55:15 +00:00
} else {
2016-11-02 19:22:45 +00:00
value = opt.substr(pos + 1);
opt = opt.substr(0, pos);
}
2016-11-25 12:55:15 +00:00
if (!values.empty() && std::find(values.begin(), values.end(), value) == values.end()) {
2016-11-02 19:22:45 +00:00
throw value_error("Invalid value '" + value + "' for argument " + string{opt});
2016-11-25 12:55:15 +00:00
}
2016-11-02 19:22:45 +00:00
return value;
}
/**
* Parse and validate passed arguments and flags
*/
2016-11-25 12:55:15 +00:00
void cliparser::parse(const string& input, const string& input_next) {
2016-11-02 19:22:45 +00:00
if (m_skipnext) {
m_skipnext = false;
2016-11-25 12:55:15 +00:00
if (!input_next.empty()) {
2016-11-02 19:22:45 +00:00
return;
2016-11-25 12:55:15 +00:00
}
2016-11-02 19:22:45 +00:00
}
for (auto&& opt : m_opts) {
if (is(input, opt.flag, opt.flag_long)) {
if (opt.token.empty()) {
2016-11-25 12:55:15 +00:00
m_optvalues.insert(make_pair(opt.flag_long.substr(2), ""));
2016-11-02 19:22:45 +00:00
} else {
auto value = parse_value(input, input_next, opt.values);
m_skipnext = (value == input_next);
2016-11-25 12:55:15 +00:00
m_optvalues.insert(make_pair(opt.flag_long.substr(2), value));
2016-11-02 19:22:45 +00:00
}
return;
}
}
if (input.compare(0, 1, "-") == 0) {
throw argument_error("Unrecognized option " + input);
}
}
2016-11-19 05:22:44 +00:00
POLYBAR_NS_END