pflib v3.9.4-7-gb2e7f4f
Pretty Fine HGCROC Interaction Library
Loading...
Searching...
No Matches
Menu.h
1#ifndef PFLIB_TOOL_MENU_H
2#define PFLIB_TOOL_MENU_H
3
4#include <stdio.h>
5#include <string.h>
6
7#include <functional>
8#include <iomanip>
9#include <iostream>
10#include <list>
11#include <string>
12#include <vector>
13
14#include "pflib/Exception.h"
15#include "pflib/logging/Logging.h"
16
17namespace pflib::menu {
18
27class BaseMenu {
28 static std::string history_filepath_;
29
30 public:
34 static void set_history_filepath(std::string fp);
35
42 static void open_history();
43
47 static void close_history();
48
65 static std::string readline(const std::string& prompt,
66 const std::string& defval,
67 bool preserve_last_blank = false);
68
77 static std::string readline_nosplit(const std::string& prompt,
78 const std::string& defval);
87 static std::string readline(const std::string& prompt);
88
98 static std::string readline(const std::string& prompt,
99 const std::vector<std::string>& opts,
100 const std::string& def = "");
101
112 static std::string default_path(const std::string& name,
113 const std::string& extension = "");
114
117
126 static std::string readline_path(const std::string& name,
127 const std::string& extension = "");
128
139
149 static int readline_int(const std::string& prompt);
150
161 static int readline_int(const std::string& prompt, int aval,
162 bool ashex = false);
163
174 static double readline_float(const std::string& prompt);
175
188 static bool readline_bool(const std::string& prompt, bool aval);
189
200 static std::string readline_cmd();
201
207 static void add_to_command_queue(const std::string& str);
208
209 protected:
217 void add_to_history(const std::string& cmd) const;
218
221
225
228
229 static ::pflib::logging::logger the_log_;
230
231 private:
246 static char* matcher(const char* text, int state);
247}; // BaseMenu
248
275template <typename T>
276class Menu : public BaseMenu {
277 public:
279 using TargetHandle = T;
285
295
307 Menu* line(const char* name, const char* desc, SingleTargetCommand ex,
308 unsigned int category = 0) {
309 lines_.emplace_back(name, desc, ex, category);
310 return this;
311 }
312
327 Menu* line(const char* name, const char* desc, MultipleTargetCommands ex,
328 unsigned int category = 0) {
329 lines_.emplace_back(name, desc, ex, category);
330 return this;
331 }
332
353 std::shared_ptr<Menu> submenu(const char* name, const char* desc,
354 RenderFuncType f = 0,
355 unsigned int category = 0) {
356 auto sb = std::make_shared<Menu>(f, 0, name, this);
357 lines_.emplace_back(name, desc, sb, category);
358 return sb;
359 }
360
364 static Menu* root() {
365 static Menu root;
366 return &root;
367 }
368
376 void build() {
377 // go through menu options and add exit
378 for (Line& l : lines_) l.build();
379 lines_.emplace_back("EXIT", "leave this menu");
380 lines_.emplace_back("HELP", "print help for this menu",
381 [this](TargetHandle tgt) { this->render(tgt); });
382 lines_.emplace_back("PWD", "print current menu path",
383 [this](TargetHandle tgt) {
384 pflib_log(info) << "Current menu: ";
385 this->print_path();
387 });
388 }
389
400 static void run(TargetHandle tgt) {
402 root()->build();
403 root()->steer(tgt);
405 }
406
408 Menu(const Menu&) = delete;
410 void operator=(const Menu&) = delete;
411
415 Menu(RenderFuncType f = 0, unsigned int hidden_categories = 0,
416 const char* name = "", Menu* parent = nullptr)
417 : render_func_{f},
418 hidden_categories_{hidden_categories},
419 name_(name),
420 parent_(parent) {}
421
423 void hide(unsigned int categories) {
424 hidden_categories_ = categories;
425 for (auto& l : lines_) {
426 l.hide(categories);
427 }
428 }
429
433 void print(std::ostream& s, int indent = 0) const {
434 for (const auto& l : lines_) {
435 if ((l.category() & hidden_categories_) == 0) {
436 l.print(s, indent);
437 }
438 }
439 }
440
446 if (parent_ != nullptr) {
448 s << name_ << "/";
449 } else {
450 s << "/"; // root menu
451 }
452 }
453
463 void render(TargetHandle tgt) const {
464 if (render_func_) {
465 render_func_(tgt);
466 }
467 std::cout << "\n";
468 for (const auto& l : lines_) {
469 if ((l.category() & hidden_categories_) == 0) {
470 std::cout << l << std::endl;
471 }
472 }
473 }
474
489 void enter(TargetHandle tgt) const {
490 if (cmdTextQueue_.empty()) {
491 // copy over command options for tab complete
492 this->cmd_options_ = this->command_options();
493 this->render(tgt);
494 }
495 }
496
517 void steer(TargetHandle p_target) const {
518 enter(p_target);
519 const Line* theMatch = 0;
520 do {
521 std::string request = readline_cmd();
522 theMatch = 0;
523 // check for a unique match...
524 int nmatch = 0;
525 for (size_t i = 0; i < lines_.size(); i++)
526 if (strcasecmp(request.c_str(), lines_[i].name()) == 0) {
527 theMatch = &(lines_[i]);
528 nmatch++;
529 }
530 if (nmatch > 1) theMatch = 0;
531 // ok
532 if (theMatch == 0)
533 printf(" Command '%s' not understood.\n\n", request.c_str());
534 else {
535 add_to_history(theMatch->name());
536 if (theMatch->execute(p_target)) {
537 // resume control when the chosen line was a submenu
538 enter(p_target);
539 }
540 }
541 } while (theMatch == 0 or not theMatch->empty());
542 }
543
583 static std::shared_ptr<Menu> menu(const char* name, const char* desc,
584 RenderFuncType render_func = 0,
585 unsigned int category = 0) {
586 return root()->submenu(name, desc, render_func, category);
587 }
588
589 private:
597 v.reserve(lines_.size());
598 for (const auto& l : lines_) {
599 if ((l.category() & hidden_categories_) == 0) {
600 v.push_back(l.name());
601 }
602 }
603 return v;
604 }
605
606 private:
622 class Line {
623 public:
625 Line(const char* n, const char* d, SingleTargetCommand f,
626 unsigned int category = 0)
627 : name_(n),
628 desc_(d),
629 sub_menu_{nullptr},
630 cmd_(f),
631 mult_cmds_{0},
634 Line(const char* n, const char* d, MultipleTargetCommands f,
635 unsigned int category = 0)
636 : name_(n),
637 desc_(d),
638 sub_menu_{nullptr},
639 mult_cmds_{f},
642 Line(const char* n, const char* d, std::shared_ptr<Menu> m,
643 unsigned int category = 0)
644 : name_(n),
645 desc_(d),
646 sub_menu_(m),
647 cmd_(0),
648 mult_cmds_{0},
656 Line(const char* n, const char* d)
657 : name_(n),
658 desc_(d),
659 sub_menu_{nullptr},
660 cmd_(0),
661 mult_cmds_{0},
662 category_{0} {}
663
677 bool execute(TargetHandle p) const {
678 if (sub_menu_) {
679 sub_menu_->steer(p);
680 return true;
681 } else if (cmd_ or mult_cmds_) {
682 try {
683 if (cmd_)
684 cmd_(p);
685 else
686 mult_cmds_(name_, p);
687 } catch (const pflib::Exception& e) {
688 pflib_log(error) << "[" << e.name() << "] : " << e.message();
689 } catch (const std::exception& e) {
690 pflib_log(error) << "Unknown Exception " << e.what();
691 }
692 }
693 // empty and command lines don't need the parent menu
694 // to reset the command options
695 return false;
696 }
697
701 bool empty() const { return !sub_menu_ and cmd_ == 0 and mult_cmds_ == 0; }
702
709 void build() {
710 if (sub_menu_) sub_menu_->build();
711 }
712
716 void hide(unsigned int categories) {
717 if (sub_menu_) sub_menu_->hide(categories);
718 }
719
721 const char* name() const { return name_; }
723 const char* desc() const { return desc_; }
725 unsigned int category() const { return category_; }
726
730 friend std::ostream& operator<<(std::ostream& s, const Line& l) {
731 return (s << " " << std::left << std::setw(12) << l.name() << " "
732 << l.desc());
733 }
734
739 void print(std::ostream& s, int indent = 0) const {
740 for (std::size_t i{0}; i < indent; i++) s << " ";
741 s << *this << "\n";
742 if (sub_menu_) {
743 sub_menu_->print(s, indent + 2);
744 }
745 }
746
747 private:
749 const char* name_;
751 const char* desc_;
759 unsigned int category_;
760
761 }; // Line
762
763 private:
769 unsigned int hidden_categories_;
774}; // Menu
775
776} // namespace pflib::menu
777
778#endif // PFLIB_TOOL_MENU_H
T c_str(T... args)
PFlib.
Definition Exception.h:12
const std::string & message() const
Get the message of the exception.
Definition Exception.h:52
virtual const char * what() const
The error message.
Definition Exception.h:76
const std::string & name() const
Get the name of the exception.
Definition Exception.h:46
Type-less menu base for common tasks.
Definition Menu.h:27
static std::string default_path(const std::string &name, const std::string &extension="")
Create a default path from the output directory and timestamp format parameters.
Definition Menu.cc:175
static void open_history()
open history and read from file (if it exists)
Definition Menu.cc:53
static std::list< std::string > cmdTextQueue_
the ordered list of commands to be executed from a script file
Definition Menu.h:220
void add_to_history(const std::string &cmd) const
Add a command to the history of commands that have been executed.
Definition Menu.cc:76
static std::vector< std::string > cmd_options_
the current command options (for interfacing with readline's tab completion)
Definition Menu.h:224
static std::string readline_nosplit(const std::string &prompt, const std::string &defval)
Get a raw input value without the additional splitting and modifications done in base readline.
Definition Menu.cc:138
static int readline_int(const std::string &prompt)
Read an integer parameter without a default.
Definition Menu.cc:202
static void set_history_filepath(std::string fp)
Decide where the filepath for reading/writing the history should be.
Definition Menu.cc:30
static std::string timestamp_format
format of timestamp to append to default path
Definition Menu.h:138
static double readline_float(const std::string &prompt)
Read a float parameter with a default.
Definition Menu.cc:206
static std::string readline_path(const std::string &name, const std::string &extension="")
Read a path from the user using default_path to generate a default value.
Definition Menu.cc:193
static void close_history()
close up history
Definition Menu.cc:70
static const std::vector< std::string > * rl_comp_opts_
a pointer to the list of options when attempting readline completion
Definition Menu.h:227
static std::string readline_cmd()
Read a command from the menu.
Definition Menu.cc:229
static bool readline_bool(const std::string &prompt, bool aval)
Read a bool parameter with a default.
Definition Menu.cc:219
static char * matcher(const char *text, int state)
matcher function following readline's function signature
Definition Menu.cc:231
static void add_to_command_queue(const std::string &str)
Add to the queue of commands to execute automatically.
Definition Menu.cc:80
static std::string readline(const std::string &prompt, const std::string &defval, bool preserve_last_blank=false)
Read in a parameter using the default value if nothing provided.
Definition Menu.cc:84
static std::string output_directory
output directory to include in default path
Definition Menu.h:116
A command in the menu.
Definition Menu.h:622
void build()
build this line
Definition Menu.h:709
void print(std::ostream &s, int indent=0) const
More specialized printing function to make it easier to recursively printout entire menu with descrip...
Definition Menu.h:739
const char * desc_
short description for what this line is
Definition Menu.h:751
Line(const char *n, const char *d, MultipleTargetCommands f, unsigned int category=0)
define a menu line that uses a multiple command function
Definition Menu.h:634
bool execute(TargetHandle p) const
Execute this line.
Definition Menu.h:677
Line(const char *n, const char *d, SingleTargetCommand f, unsigned int category=0)
define a menu line that uses a single target command
Definition Menu.h:625
Line(const char *n, const char *d, std::shared_ptr< Menu > m, unsigned int category=0)
define a menu line that enters a sub menu
Definition Menu.h:642
friend std::ostream & operator<<(std::ostream &s, const Line &l)
Overload output stream operator for easier printing.
Definition Menu.h:730
unsigned int category_
category integer for disabling menu lines by groups
Definition Menu.h:759
const char * desc() const
short description to print with menu
Definition Menu.h:723
void hide(unsigned int categories)
pass on configuration on which categories to hide
Definition Menu.h:716
const char * name() const
name of this line to select it
Definition Menu.h:721
bool empty() const
Check if this line is an empty one.
Definition Menu.h:701
Line(const char *n, const char *d)
define an empty menu line with only a name and description
Definition Menu.h:656
MultipleTargetCommands mult_cmds_
function handling multiple commands to execute (if exists)
Definition Menu.h:757
SingleTargetCommand cmd_
function pointer to execute (if exists)
Definition Menu.h:755
const char * name_
the name of this line
Definition Menu.h:749
std::shared_ptr< Menu > sub_menu_
pointer to sub menu (if it exists)
Definition Menu.h:753
unsigned int category() const
category int for hiding if certain categories are disabled
Definition Menu.h:725
A menu to execute commands with a specific target.
Definition Menu.h:276
void steer(TargetHandle p_target) const
give control over the target to this menu
Definition Menu.h:517
std::vector< Line > lines_
lines in this menu
Definition Menu.h:765
void operator=(const Menu &)=delete
no copying
Menu * parent_
pointer to parent menu (nullptr for root)
Definition Menu.h:773
Menu(RenderFuncType f=0, unsigned int hidden_categories=0, const char *name="", Menu *parent=nullptr)
Construct a menu with a rendering function.
Definition Menu.h:415
virtual std::vector< std::string > command_options() const
Provide the list of command options.
Definition Menu.h:595
void render(TargetHandle tgt) const
render this menu to the user
Definition Menu.h:463
std::string name_
name of this menu (empty for root)
Definition Menu.h:771
void hide(unsigned int categories)
set hidden categories
Definition Menu.h:423
void print(std::ostream &s, int indent=0) const
Print menu without running it.
Definition Menu.h:433
void build()
Go through and build each of the lines in this menu.
Definition Menu.h:376
RenderFuncType render_func_
function pointer to render the menu prompt
Definition Menu.h:767
void print_path(std::ostream &s=std::cout) const
Print out the current path, showing the parents and where we are in the menu.
Definition Menu.h:445
Menu * line(const char *name, const char *desc, SingleTargetCommand ex, unsigned int category=0)
declare a single target command with thei nput name and desc
Definition Menu.h:307
static std::shared_ptr< Menu > menu(const char *name, const char *desc, RenderFuncType render_func=0, unsigned int category=0)
Construct a new menu with the root as parent and optional rendering.
Definition Menu.h:583
unsigned int hidden_categories_
bit-wise OR of any category integers that should not be displayed
Definition Menu.h:769
static void run(TargetHandle tgt)
Call this function when ready to run.
Definition Menu.h:400
Menu * line(const char *name, const char *desc, MultipleTargetCommands ex, unsigned int category=0)
declare a single target command with the input name and desc
Definition Menu.h:327
void enter(TargetHandle tgt) const
entered this menu
Definition Menu.h:489
static Menu * root()
Retreve a pointer to the root menu.
Definition Menu.h:364
Menu(const Menu &)=delete
no copying
std::shared_ptr< Menu > submenu(const char *name, const char *desc, RenderFuncType f=0, unsigned int category=0)
declare a sub menu of us with input name and desc
Definition Menu.h:353
T TargetHandle
the type of target this menu will hold and pass around
Definition Menu.h:279
T empty(T... args)
T endl(T... args)
T left(T... args)
T make_shared(T... args)
T push_back(T... args)
T reserve(T... args)
T setw(T... args)