#include "Console.h" #include #include using std::string; using std::vector; using std::ostream; using std::istream; using std::flush; using std::getline; using boost::optional; using boost::none; using std::function; using namespace cpputils; IOStreamConsole::IOStreamConsole(): IOStreamConsole(std::cout, std::cin) { } IOStreamConsole::IOStreamConsole(ostream &output, istream &input): _output(output), _input(input) { } optional parseInt(const string &str) { try { string trimmed = str; boost::algorithm::trim(trimmed); int parsed = std::stoi(str); if (std::to_string(parsed) != trimmed) { return none; } return parsed; } catch (const std::invalid_argument &e) { return none; } catch (const std::out_of_range &e) { return none; } } function(const std::string &input)> parseUIntWithMinMax(unsigned int min, unsigned int max) { return [min, max] (const string &input) { optional parsed = parseInt(input); if (parsed == none) { return optional(none); } unsigned int value = static_cast(*parsed); if (value < min || value > max) { return optional(none); } return optional(value); }; } template Return IOStreamConsole::_askForChoice(const string &question, function (const string&)> parse) { optional choice = none; do { _output << question << flush; string choiceStr; getline(_input, choiceStr); choice = parse(choiceStr); } while(choice == none); return *choice; } unsigned int IOStreamConsole::ask(const string &question, const vector &options) { if(options.size() == 0) { throw std::invalid_argument("options should have at least one entry"); } _output << "\n" << question << "\n"; for (unsigned int i = 0; i < options.size(); ++i) { _output << " [" << (i+1) << "] " << options[i] << "\n"; } int choice = _askForChoice("Your choice [1-" + std::to_string(options.size()) + "]: ", parseUIntWithMinMax(1, options.size())); return choice-1; } function(const string &input)> parseYesNo() { return [] (const string &input) { string trimmed = input; boost::algorithm::trim(trimmed); if(trimmed == "Y" || trimmed == "y" || trimmed == "Yes" || trimmed == "yes") { return optional(true); } else if (trimmed == "N" || trimmed == "n" || trimmed == "No" || trimmed == "no") { return optional(false); } else { return optional(none); } }; } bool IOStreamConsole::askYesNo(const string &question) { _output << "\n" << question << "\n"; return _askForChoice("Your choice [y/n]: ", parseYesNo()); } void IOStreamConsole::print(const std::string &output) { _output << output << std::flush; }