pflib v2.7.0-1-gd371ab6a
Polarfire Interaction Library
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 <list>
8#include <string>
9#include <vector>
10#include <functional>
11#include <iostream>
12#include <iomanip>
13
14#ifndef PFLIB_TEST_MENU
15#include "pflib/Exception.h"
16#endif
17
26class BaseMenu {
27 public:
44 static std::string readline(const std::string& prompt,
45 const std::string& defval,
46 bool preserve_last_blank = false);
47
56 static std::string readline_nosplit(const std::string& prompt,
57 const std::string& defval);
66 static std::string readline(const std::string& prompt);
67
75 static std::string readline(const std::string& prompt, const std::vector<std::string>& opts);
76
86 static int readline_int(const std::string& prompt);
87
98 static int readline_int(const std::string& prompt, int aval);
99
110 static double readline_float(const std::string& prompt);
111
124 static bool readline_bool(const std::string& prompt, bool aval);
125
136 static std::string readline_cmd();
137
143 static void add_to_command_queue(const std::string& str);
144
145 protected:
153 void add_to_history(const std::string& cmd) const;
154
157
160
163
164 private:
179 static char* matcher(const char* text, int state);
180}; // BaseMenu
181
209template <typename T, typename H = T*>
210class Menu : public BaseMenu {
211 public:
213 using TargetType = T;
215 using TargetHandle = H;
220
230
241 Menu* line(const char* name, const char* desc, SingleTargetCommand ex) {
242 lines_.emplace_back(name,desc,ex);
243 return this;
244 }
245
259 Menu* line(const char* name, const char* desc, MultipleTargetCommands ex) {
260 lines_.emplace_back(name,desc,ex);
261 return this;
262 }
263
287 Menu* submenu(const char* name, const char* desc, RenderFuncType f = 0) {
288 auto sb = new Menu(f);
289 lines_.emplace_back(name,desc,sb); // Line takes ownership
290 return sb;
291 }
292
296 static Menu* root() {
297 static Menu root;
298 return &root;
299 }
300
308 void render() {
309 // go through menu options and add exit
310 for (Line& l : lines_) l.render();
311 lines_.emplace_back("EXIT","leave this menu");
312 }
313
324 static void run(TargetHandle tgt) {
325 root()->render();
326 root()->steer(tgt);
327 }
328
330 Menu(const Menu&) = delete;
332 void operator=(const Menu&) = delete;
333
338
359 void steer(TargetHandle p_target) const {
360 this->cmd_options_ = this->command_options(); // we are the captain now
361 const Line* theMatch = 0;
362 do {
363 if (render_func_ != 0) {
364 this->render_func_(p_target);
365 }
366 // if cmd text queue is empty, then print menu for interactive user
367 if (this->cmdTextQueue_.empty()) {
368 printf("\n");
369 for (const auto& l : lines_)
370 std::cout << l << std::endl;
371 }
372 std::string request = readline_cmd();
373 theMatch = 0;
374 // check for a unique match...
375 int nmatch = 0;
376 for (size_t i = 0; i < lines_.size(); i++)
377 if (strcasecmp(request.c_str(), lines_[i].name()) == 0) {
378 theMatch = &(lines_[i]);
379 nmatch++;
380 }
381 if (nmatch > 1) theMatch = 0;
382 // ok
383 if (theMatch == 0)
384 printf(" Command '%s' not understood.\n\n", request.c_str());
385 else {
386 add_to_history(theMatch->name());
387 if (theMatch->execute(p_target)) {
388 // resume control when the chosen line was a submenu
389 this->cmd_options_ = this->command_options();
390 }
391 }
392 } while (theMatch == 0 or not theMatch->empty());
393 }
394
432 static Menu* menu(const char* name, const char* desc,
433 RenderFuncType render_func = 0) {
434 return root()->submenu(name,desc,render_func);
435 }
436
437 private:
445 v.reserve(lines_.size());
446 for (const auto& l : lines_) v.push_back(l.name());
447 return v;
448 }
449
450 private:
466 class Line {
467 public:
469 Line(const char* n, const char* d, SingleTargetCommand f)
470 : name_(n), desc_(d), sub_menu_{0}, cmd_(f), mult_cmds_{0} {}
472 Line(const char* n, const char* d, MultipleTargetCommands f)
473 : name_(n), desc_(d), sub_menu_{0}, mult_cmds_{f} {}
475 Line(const char* n, const char* d, Menu* m)
476 : name_(n), desc_(d), sub_menu_(m), cmd_(0), mult_cmds_{0} {}
483 Line(const char* n, const char* d)
484 : name_(n), desc_(d), sub_menu_{0}, cmd_(0), mult_cmds_{0} {}
485
489 Line(Line&& l) noexcept
490 : name_{l.name_},
491 desc_{l.desc_},
492 sub_menu_{l.sub_menu_},
493 cmd_{l.cmd_},
494 mult_cmds_{l.mult_cmds_}
495 {
496 l.sub_menu_ = 0;
497 }
498
499 Line(const Line& l) = default;
500
501 ~Line() {
502 if (sub_menu_) delete sub_menu_;
503 }
504
518 bool execute(TargetHandle p) const {
519 if (sub_menu_) {
520 sub_menu_->steer(p);
521 return true;
522 } else if (cmd_ or mult_cmds_) {
523 try {
524 if (cmd_) cmd_(p);
525 else mult_cmds_(name_,p);
526#ifndef PFLIB_TEST_MENU
527 } catch(const pflib::Exception& e) {
528 std::cerr << " pflib ERR [" << e.name()
529 << "] : " << e.message() << std::endl;
530#endif
531 } catch(const std::exception& e) {
532 std::cerr << " Unknown Exception " << e.what() << std::endl;
533 }
534 }
535 // empty and command lines don't need the parent menu
536 // to reset the command options
537 return false;
538 }
539
543 bool empty() const {
544 return !sub_menu_ and cmd_ == 0 and mult_cmds_ == 0;
545 }
546
550 void render() {
551 if (sub_menu_) sub_menu_->render();
552 }
553
555 const char* name() const { return name_; }
557 const char* desc() const { return desc_; }
558 friend std::ostream& operator<<(std::ostream& s, const Line& l) {
559 return (s << " " << std::left << std::setw(12) << l.name()
560 << " " << l.desc());
561 }
562 private:
564 const char* name_;
566 const char* desc_;
573 }; // Line
574
575 private:
580}; // Menu
581
582#endif // PFLIB_TOOL_MENU_H
T c_str(T... args)
Type-less menu base for common tasks.
Definition: Menu.h:26
static std::vector< std::string > cmd_options_
the current command options (for interfacing with readline's tab completion)
Definition: Menu.h:159
void add_to_history(const std::string &cmd) const
Add a command to the history of commands that have been executed.
Definition: Menu.cc:18
static std::string readline_cmd()
Read a command from the menu.
Definition: Menu.cc:144
static std::list< std::string > cmdTextQueue_
the ordered list of commands to be executed from a script file
Definition: Menu.h:156
static char * matcher(const char *text, int state)
matcher function following readline's function signature
Definition: Menu.cc:148
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:80
static const std::vector< std::string > * rl_comp_opts_
a pointer to the list of options when attempting readline completion
Definition: Menu.h:162
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:26
static bool readline_bool(const std::string &prompt, bool aval)
Read a bool parameter with a default.
Definition: Menu.cc:134
static double readline_float(const std::string &prompt)
Read a float parameter with a default.
Definition: Menu.cc:120
static int readline_int(const std::string &prompt)
Read an integer parameter without a default.
Definition: Menu.cc:112
static void add_to_command_queue(const std::string &str)
Add to the queue of commands to execute automatically.
Definition: Menu.cc:22
A command in the menu.
Definition: Menu.h:466
Line(const char *n, const char *d)
define an empty menu line with only a name and description
Definition: Menu.h:483
const char * name() const
name of this line to select it
Definition: Menu.h:555
bool empty() const
Check if this line is an empty one.
Definition: Menu.h:543
void render()
add an exit line if this is a menu, otherwise do nothing
Definition: Menu.h:550
Menu * sub_menu_
pointer to sub menu (if it exists)
Definition: Menu.h:568
Line(const char *n, const char *d, SingleTargetCommand f)
define a menu line that uses a single target command
Definition: Menu.h:469
Line(const char *n, const char *d, MultipleTargetCommands f)
define a menu line that uses a multiple command function
Definition: Menu.h:472
MultipleTargetCommands mult_cmds_
function handling multiple commands to execute (if exists)
Definition: Menu.h:572
bool execute(TargetHandle p) const
Execute this line.
Definition: Menu.h:518
Line(Line &&l) noexcept
noexcept move constructor allows std::vector to use it when expanding capacity
Definition: Menu.h:489
const char * desc() const
short description to print with menu
Definition: Menu.h:557
SingleTargetCommand cmd_
function pointer to execute (if exists)
Definition: Menu.h:570
const char * desc_
short description for what this line is
Definition: Menu.h:566
Line(const char *n, const char *d, Menu *m)
define a menu line that enters a sub menu
Definition: Menu.h:475
const char * name_
the name of this line
Definition: Menu.h:564
A menu to execute commands with a specific target.
Definition: Menu.h:210
Menu(RenderFuncType f=0)
Construct a menu with a rendering function.
Definition: Menu.h:337
static void run(TargetHandle tgt)
Call this function when ready to run.
Definition: Menu.h:324
void render()
Go through and render each of the lines in this menu.
Definition: Menu.h:308
Menu * line(const char *name, const char *desc, MultipleTargetCommands ex)
declare a single target command with the input name and desc
Definition: Menu.h:259
Menu(const Menu &)=delete
no copying
static Menu * menu(const char *name, const char *desc, RenderFuncType render_func=0)
Construct a new menu with the root as parent and optional rendering.
Definition: Menu.h:432
void steer(TargetHandle p_target) const
give control over the target to this menu
Definition: Menu.h:359
static Menu * root()
Retreve a pointer to the root menu.
Definition: Menu.h:296
std::vector< Line > lines_
lines in this menu
Definition: Menu.h:577
virtual std::vector< std::string > command_options() const
Provide the list of command options.
Definition: Menu.h:443
H TargetHandle
the type of handle we use to access the target
Definition: Menu.h:215
T TargetType
the type of target this menu points to
Definition: Menu.h:213
Menu * submenu(const char *name, const char *desc, RenderFuncType f=0)
declare a sub menu of us with input name and desc
Definition: Menu.h:287
Menu * line(const char *name, const char *desc, SingleTargetCommand ex)
declare a single target command with thei nput name and desc
Definition: Menu.h:241
RenderFuncType render_func_
function pointer to render the menu prompt
Definition: Menu.h:579
void operator=(const Menu &)=delete
no copying
PFlib.
Definition: Exception.h:12
const std::string & message() const
Get the message of the exception.
Definition: Exception.h:53
virtual const char * what() const
The error message.
Definition: Exception.h:77
const std::string & name() const
Get the name of the exception.
Definition: Exception.h:47
T endl(T... args)
T left(T... args)
T push_back(T... args)
T reserve(T... args)
T setw(T... args)