Initial Commit
This commit is contained in:
		
							
								
								
									
										14
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | { | ||||||
|  |     "files.associations": { | ||||||
|  |         "cstring": "cpp", | ||||||
|  |         "string": "cpp", | ||||||
|  |         "unordered_map": "cpp", | ||||||
|  |         "vector": "cpp", | ||||||
|  |         "algorithm": "cpp", | ||||||
|  |         "functional": "cpp", | ||||||
|  |         "random": "cpp", | ||||||
|  |         "tuple": "cpp", | ||||||
|  |         "type_traits": "cpp", | ||||||
|  |         "iostream": "cpp" | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | MIT License | ||||||
|  |  | ||||||
|  | Copyright (c) 2024 René Amthor (tobid7) | ||||||
|  |  | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  | of this software and associated documentation files (the "Software"), to deal | ||||||
|  | in the Software without restriction, including without limitation the rights | ||||||
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | copies of the Software, and to permit persons to whom the Software is | ||||||
|  | furnished to do so, subject to the following conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be included in all | ||||||
|  | copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  | SOFTWARE. | ||||||
							
								
								
									
										5
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | # cli-fancy library | ||||||
|  |  | ||||||
|  | Single header library for cli apps | ||||||
|  |  | ||||||
|  | Used in ctrff and npi-build | ||||||
							
								
								
									
										267
									
								
								include/cli-fancy.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										267
									
								
								include/cli-fancy.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,267 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | MIT License | ||||||
|  |  | ||||||
|  | Copyright (c) 2024 René Amthor (tobid7) | ||||||
|  |  | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  | of this software and associated documentation files (the "Software"), to deal | ||||||
|  | in the Software without restriction, including without limitation the rights | ||||||
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | copies of the Software, and to permit persons to whom the Software is | ||||||
|  | furnished to do so, subject to the following conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be included in all | ||||||
|  | copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  | SOFTWARE. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include <algorithm> | ||||||
|  | #include <cstring> | ||||||
|  | #include <functional> | ||||||
|  | #include <iostream> | ||||||
|  | #include <string> | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | // CLI FANCY | ||||||
|  | namespace cf7 { | ||||||
|  | namespace sym { | ||||||
|  | const std::string arrow = ""; | ||||||
|  | } | ||||||
|  | class col { | ||||||
|  |  public: | ||||||
|  |   col() { m_isres = true; } | ||||||
|  |   col(bool fg, unsigned char r, unsigned char g, unsigned char b) { | ||||||
|  |     m_isres = false; | ||||||
|  |     m_r = r; | ||||||
|  |     m_g = g; | ||||||
|  |     m_b = b; | ||||||
|  |     m_fg = fg; | ||||||
|  |   } | ||||||
|  |   col(unsigned char r, unsigned char g, unsigned char b) { | ||||||
|  |     m_isres = false; | ||||||
|  |     m_r = r; | ||||||
|  |     m_g = g; | ||||||
|  |     m_b = b; | ||||||
|  |     // Default Fancy Api uses GetAs | ||||||
|  |     m_fg = false; | ||||||
|  |   } | ||||||
|  |   ~col() = default; | ||||||
|  |  | ||||||
|  |   std::string Get() const { return GetAs(m_fg); } | ||||||
|  |  | ||||||
|  |   std::string GetAs(bool fg) const { | ||||||
|  |     if (m_isres) { | ||||||
|  |       return "\033[00m"; | ||||||
|  |     } | ||||||
|  |     std::string col = "\033["; | ||||||
|  |     col += fg ? "38" : "48"; | ||||||
|  |     col += ";2;"; | ||||||
|  |     col += std::to_string(m_r) + ";"; | ||||||
|  |     col += std::to_string(m_g) + ";"; | ||||||
|  |     col += std::to_string(m_b) + "m"; | ||||||
|  |     return col; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   operator std::string() const { return Get(); } | ||||||
|  |   operator const char*() const { | ||||||
|  |     /// CREATE DYNAMIC BUFFER TO ALWAYS RETURN STABLE CONST CHAR | ||||||
|  |     static char buf[32]; | ||||||
|  |     strcpy(buf, Get().c_str()); | ||||||
|  |     buf[sizeof(buf) - 1] = '\0'; | ||||||
|  |     return buf; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  private: | ||||||
|  |   bool m_isres = true; | ||||||
|  |   bool m_fg = false; | ||||||
|  |   unsigned char m_r = 0; | ||||||
|  |   unsigned char m_g = 0; | ||||||
|  |   unsigned char m_b = 0; | ||||||
|  | }; | ||||||
|  | void PrintFancy(const std::vector<std::pair<std::string, col>>& e) { | ||||||
|  |   std::cout << col(); | ||||||
|  |   for (int i = 0; i < e.size(); i++) { | ||||||
|  |     std::cout << e[i].second.GetAs(false) << col(true, 255, 255, 255); | ||||||
|  |     std::cout << " " << e[i].first << " "; | ||||||
|  |     if (i == e.size() - 1) { | ||||||
|  |       std::cout << col() << e[i].second.GetAs(true) << sym::arrow; | ||||||
|  |     } else { | ||||||
|  |       std::cout << e[i + 1].second.GetAs(false) << e[i].second.GetAs(true) | ||||||
|  |                 << sym::arrow; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   std::cout << col() << std::endl; | ||||||
|  | } | ||||||
|  | class command { | ||||||
|  |  public: | ||||||
|  |   using ArgumentList = std::vector<std::pair<std::string, std::string>>; | ||||||
|  |   using Function = std::function<void(const ArgumentList&)>; | ||||||
|  |   class sub { | ||||||
|  |    public: | ||||||
|  |     sub(const std::string& _short, const std::string& _long, | ||||||
|  |         const std::string desc, bool req) { | ||||||
|  |       m_isrequired = req; | ||||||
|  |       m_long = _long; | ||||||
|  |       m_short = _short; | ||||||
|  |       m_desc = desc; | ||||||
|  |     } | ||||||
|  |     ~sub() = default; | ||||||
|  |  | ||||||
|  |     bool IsRequired() const { return m_isrequired; } | ||||||
|  |     const std::string& GetShort() const { return m_short; } | ||||||
|  |     const std::string& GetLong() const { return m_long; } | ||||||
|  |     const std::string& GetDesc() const { return m_desc; } | ||||||
|  |  | ||||||
|  |    private: | ||||||
|  |     bool m_isrequired; | ||||||
|  |     std::string m_long; | ||||||
|  |     std::string m_short; | ||||||
|  |     std::string m_desc; | ||||||
|  |   }; | ||||||
|  |   command(std::string base, std::string desc) { | ||||||
|  |     m_name = base; | ||||||
|  |     m_desc = desc; | ||||||
|  |   } | ||||||
|  |   ~command() = default; | ||||||
|  |  | ||||||
|  |   command& AddSubEntry(const sub& sub) { | ||||||
|  |     m_sub.push_back(sub); | ||||||
|  |     return *this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   command& SetFunction(Function fun) { | ||||||
|  |     m_fun = fun; | ||||||
|  |     return *this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Function Func() const { return m_fun; } | ||||||
|  |  | ||||||
|  |   static std::string GetArg(ArgumentList list, std::string arg) { | ||||||
|  |     for (const auto& it : list) { | ||||||
|  |       if (it.first == arg) { | ||||||
|  |         return it.second; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return ""; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   const std::string& GetName() const { return m_name; } | ||||||
|  |   const std::string& GetDesc() const { return m_desc; } | ||||||
|  |   const std::vector<sub>& GetArgs() const { return m_sub; } | ||||||
|  |  | ||||||
|  |  private: | ||||||
|  |   std::string m_name; | ||||||
|  |   std::string m_desc; | ||||||
|  |   std::vector<sub> m_sub; | ||||||
|  |   Function m_fun; | ||||||
|  | }; | ||||||
|  | class arg_mgr { | ||||||
|  |  public: | ||||||
|  |   arg_mgr() {} | ||||||
|  |   arg_mgr(char** args, int argc) { Parse(args, argc); } | ||||||
|  |   arg_mgr(int argc, char** args) { Parse(args, argc); } | ||||||
|  |   ~arg_mgr() = default; | ||||||
|  |  | ||||||
|  |   void SetAppInfo(const std::string& name, const std::string& ver) { | ||||||
|  |     app_name = name; | ||||||
|  |     app_version = ver; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool FindString(const std::vector<std::string>& l, std::string w) { | ||||||
|  |     auto tf = "-" + w; | ||||||
|  |     return (std::find(l.begin(), l.end(), tf) != l.end()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   std::string GetArg(std::string w, std::string def = "") { | ||||||
|  |     if (!FindString(m_args, w)) return def; | ||||||
|  |     for (size_t i = 0; i < m_args.size() - 1; i++) { | ||||||
|  |       if (m_args[i] == std::string("-" + w)) { | ||||||
|  |         return m_args[i + 1]; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return def; | ||||||
|  |   } | ||||||
|  |   void Parse(char** args, int argc) { | ||||||
|  |     for (int i = 0; i < argc; i++) { | ||||||
|  |       m_args.push_back(args[i]); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void PrintHelp(const std::string& cmd = "") { | ||||||
|  |     if (!app_name.empty() && !app_version.empty()) { | ||||||
|  |       PrintFancy({ | ||||||
|  |           std::make_pair(app_name, col(20, 20, 20)), | ||||||
|  |           std::make_pair(app_version, col(50, 50, 50)), | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |     PrintFancy({ | ||||||
|  |         std::make_pair("Build", col(40, 40, 40)), | ||||||
|  |         std::make_pair(std::string(__TIMESTAMP__), col(70, 70, 70)), | ||||||
|  |     }); | ||||||
|  |     if (!cmd.empty()) { | ||||||
|  |       for (const auto& c : m_commands) { | ||||||
|  |         if (c.GetName() == cmd) { | ||||||
|  |           PrintFancy({std::make_pair(c.GetName(), col(10, 10, 10)), | ||||||
|  |                       std::make_pair("Help", col(30, 30, 30))}); | ||||||
|  |           for (const auto& it : c.GetArgs()) { | ||||||
|  |             PrintFancy({ | ||||||
|  |                 std::make_pair("-" + it.GetShort(), col(30, 30, 30)), | ||||||
|  |                 std::make_pair("--" + it.GetLong(), col(50, 50, 50)), | ||||||
|  |                 std::make_pair(it.GetDesc(), col(70, 70, 70)), | ||||||
|  |                 std::make_pair(it.IsRequired() ? "true" : "false", | ||||||
|  |                                col(90, 90, 90)), | ||||||
|  |             }); | ||||||
|  |           } | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     PrintFancy({std::make_pair("Commands", col(30, 30, 30))}); | ||||||
|  |     for (command c : m_commands) { | ||||||
|  |       PrintFancy({ | ||||||
|  |           std::make_pair(c.GetName(), col(40, 40, 40)), | ||||||
|  |           std::make_pair(c.GetDesc(), col(60, 60, 60)), | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void Execute() { | ||||||
|  |     command::ArgumentList arglist; | ||||||
|  |     for (const auto& c : m_commands) { | ||||||
|  |       if (c.GetName() == m_args[1]) { | ||||||
|  |         for (const auto& j : c.GetArgs()) { | ||||||
|  |           if (!FindString(m_args, j.GetShort())) { | ||||||
|  |             if (j.IsRequired()) { | ||||||
|  |               PrintHelp(c.GetName()); | ||||||
|  |               return; | ||||||
|  |             } | ||||||
|  |           } else { | ||||||
|  |             arglist.push_back( | ||||||
|  |                 std::make_pair(j.GetShort(), GetArg(j.GetShort()))); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         c.Func()(arglist); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     PrintHelp(""); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void AddCommand(command cmd) { m_commands.push_back(cmd); } | ||||||
|  |  | ||||||
|  |  private: | ||||||
|  |   std::string app_name; | ||||||
|  |   std::string app_version; | ||||||
|  |   std::vector<std::string> m_args; | ||||||
|  |   std::vector<command> m_commands; | ||||||
|  | }; | ||||||
|  | }  // namespace cf7 | ||||||
		Reference in New Issue
	
	Block a user