Sygaldry
Loading...
Searching...
No Matches
sygbp-cli.hpp
1#pragma once
2/*
3Copyright 2023 Travis J. West, https://traviswest.ca, Input Devices and Music
4Interaction Laboratory (IDMIL), Centre for Interdisciplinary Research in Music
5Media and Technology (CIRMMT), McGill University, Montréal, Canada, and Univ.
6Lille, Inria, CNRS, Centrale Lille, UMR 9189 CRIStAL, F-59000 Lille, France
7
8SPDX-License-Identifier: MIT
9*/
10
11#include <memory>
12#include <string_view>
13#include <concepts>
14#include <cstdlib>
15#include "sygah-consteval.hpp"
16#include "sygah-metadata.hpp"
17#include "sygbp-osc_match_pattern.hpp"
18
19#include "commands/help.hpp"
20#include "commands/list.hpp"
21#include "commands/describe.hpp"
22#include "commands/set.hpp"
23
24namespace sygaldry { namespace sygbp {
29
30template<typename Reader, typename Logger, typename Components, typename Commands>
31struct CustomCli : name_<"CLI">
32 , author_<"Travis J. West">
33 , description_<"Generate a simple command line interface for inspecting and sending data to the bound components.">
34 , version_<"0.0.0">
35 , copyright_<"Copyright 2023 Sygaldry contributors">
36 , license_<"SPDX-License-Identifier: MIT">
37{
38 [[no_unique_address]] Logger log;
39 [[no_unique_address]] Reader reader;
40 [[no_unique_address]] Commands commands;
41
42 void init()
43 {
44 log.println("CLI enabled. Write `/help` for a list of available commands.");
45 _prompt();
46 }
47
48 // TODO: automatically size the buffers depending on the commands
49 static constexpr size_t MAX_ARGS = 5;
50 static constexpr size_t BUFFER_SIZE = 128;
51 int argc = 0;
52 char * argv[MAX_ARGS];
53 unsigned char write_pos = 0;
54 char buffer[BUFFER_SIZE];
55
56 void _try_to_match_and_execute(Components& components)
57 {
58 boost::pfr::for_each_field(commands, [&](auto& command)
59 {
60 if (not osc_match_pattern(argv[0], command.name())) return;
61 int retcode;
62 if constexpr (std::is_same_v<decltype(command), Help&>)
63 {
64 retcode = command.main(log, commands);
65 }
66 else retcode = command.main(argc, argv, log, components);
67 if (retcode != 0) _complain_about_command_failure(retcode);
68 });
69 }
70 bool _is_whitespace(char c)
71 {
72 if (c == ' ' || c == '\t' || c == '\n' || c == '\r') return true;
73 else return false;
74 }
75
76 bool _new_arg() const
77 {
78 return write_pos == 0 || buffer[write_pos-1] == 0;
79 }
80
81 bool _overflow() const
82 {
83 return argc == MAX_ARGS || write_pos == BUFFER_SIZE-1; // -1 so we can erase forward one as we write
84 }
85
86 void _prompt()
87 {
88 log.print("\r> ");
89 for (int i = 0; i < argc - 1; ++i) log.print(argv[i], " ");
90 if (argc > 0) log.print(argv[argc - 1]);
91 }
92
93 void _reset()
94 {
95 argc = 0;
96 write_pos = 0;
97 }
98
99 void _complain_about_command_failure(int retcode)
100 {
101 log.println("command failed!");
102 } // TODO
103
104 void process(const char c, Components& components)
105 {
106 if (_is_whitespace(c))
107 buffer[write_pos++] = 0;
108 else
109 {
110 buffer[write_pos] = c;
111 buffer[write_pos+1] = 0;
112 if (_new_arg())
113 argv[argc++] = &buffer[write_pos];
114 write_pos++;
115 }
116
117 if (c == '\n' || c == '\r')
118 {
119 log.print("\r\n");
120 _try_to_match_and_execute(components);
121 _reset();
122 }
123
124 if (_overflow())
125 {
126 log.println("CLI line buffer overflow!");
127 _reset();
128 }
129
130 //_prompt();
131 }
132
133 void external_sources(Components& components)
134 {
135 while(reader.ready()) process(reader.getchar(), components);
136 }
137};
138
140{
141 Help help;
142 List list;
143 Describe describe;
144 Set set;
145};
146
147template<typename Reader, typename Logger, typename Components>
149
152} }
bool osc_match_pattern(const char *pattern, const char *address)
Match an OSC address pattern against the given address.
Definition sygbp-osc_match_pattern.cpp:12
Document the author of an entity, e.g. a component or binding.
Definition sygah-metadata.hpp:39
Document the copyright statement of an entity, e.g. a component or binding.
Definition sygah-metadata.hpp:47
Document a textual description of an entity, e.g. an endpoint, component or binding.
Definition sygah-metadata.hpp:35
Document the copyright license of an entity, e.g. a component or binding.
Definition sygah-metadata.hpp:45
Document the name of an entity, e.g. an endpoint, component, or binding.
Definition sygah-metadata.hpp:33
Definition sygbp-cli.hpp:37
Definition sygbp-cli.hpp:140
Definition describe.hpp:24
Definition help.hpp:18
Definition list.hpp:21
Definition set.hpp:21
Document a textual description of the version number of an entity, e.g. a component or binding.
Definition sygah-metadata.hpp:51