Skip to content

Commit 4ba7596

Browse files
funbiscuitasuar078
andauthored
Make live autocompletion optional (#10)
Add config option to disable live autocompletion Co-authored-by: Arian Suarez <arian.suarez001@gmail.com>
1 parent ba62216 commit 4ba7596

6 files changed

Lines changed: 82 additions & 14 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Single-header CLI library intended for use in embedded systems (like STM32 or Ar
1111
* Dynamic or static allocation
1212
* Configurable memory usage
1313
* Command-to-function binding with arguments support
14-
* Live autocompletion (see demo above)
14+
* Live autocompletion (see demo above, can be disabled)
1515
* Tab (jump to end of current autocompletion) and backspace (remove char) support
1616
* History support (navigate with up and down keypress)
1717
* Any byte-stream interface is supported (for example, UART)

‎lib/include/embedded_cli.h‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,13 @@ struct EmbeddedCliConfig {
157157
* Size of buffer for cli and internal structures (in bytes).
158158
*/
159159
uint16_t cliBufferSize;
160+
161+
/**
162+
* Whether autocompletion should be enabled.
163+
* If false, autocompletion is disabled but you still can use 'tab' to
164+
* complete current command manually.
165+
*/
166+
bool enableAutoComplete;
160167
};
161168

162169
/**
@@ -165,12 +172,15 @@ struct EmbeddedCliConfig {
165172
* Returned structure is always the same so do not free and try to use it
166173
* immediately.
167174
* Default values:
168-
* -rxBufferSize = 64
169-
* -cmdBufferSize = 64
170-
* -historyBufferSize = 128
171-
* -cliBuffer = NULL (use dynamic allocation)
172-
* -cliBufferSize = 0
173-
* -maxBindingCount = 8
175+
* <ul>
176+
* <li>rxBufferSize = 64</li>
177+
* <li>cmdBufferSize = 64</li>
178+
* <li>historyBufferSize = 128</li>
179+
* <li>cliBuffer = NULL (use dynamic allocation)</li>
180+
* <li>cliBufferSize = 0</li>
181+
* <li>maxBindingCount = 8</li>
182+
* <li>enableAutoComplete = true</li>
183+
* </ul>
174184
* @return configuration for cli creation
175185
*/
176186
EmbeddedCliConfig *embeddedCliDefaultConfig(void);

‎lib/src/embedded_cli.c‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@
5252
*/
5353
#define CLI_FLAG_DIRECT_PRINT 0x10u
5454

55+
/**
56+
* Indicates that live autocompletion is enabled
57+
*/
58+
#define CLI_FLAG_AUTOCOMPLETE_ENABLED 0x20u
59+
5560
typedef struct EmbeddedCliImpl EmbeddedCliImpl;
5661
typedef struct AutocompletedCommand AutocompletedCommand;
5762
typedef struct FifoBuf FifoBuf;
@@ -373,6 +378,7 @@ EmbeddedCliConfig *embeddedCliDefaultConfig(void) {
373378
defaultConfig.cliBuffer = NULL;
374379
defaultConfig.cliBufferSize = 0;
375380
defaultConfig.maxBindingCount = 8;
381+
defaultConfig.enableAutoComplete = true;
376382
return &defaultConfig;
377383
}
378384

@@ -434,6 +440,9 @@ EmbeddedCli *embeddedCliNew(EmbeddedCliConfig *config) {
434440
if (allocated)
435441
SET_FLAG(impl->flags, CLI_FLAG_ALLOCATED);
436442

443+
if (config->enableAutoComplete)
444+
SET_FLAG(impl->flags, CLI_FLAG_AUTOCOMPLETE_ENABLED);
445+
437446
impl->rxBuffer.size = config->rxBufferSize;
438447
impl->rxBuffer.front = 0;
439448
impl->rxBuffer.back = 0;
@@ -936,6 +945,9 @@ static AutocompletedCommand getAutocompletedCommand(EmbeddedCli *cli, const char
936945
static void printLiveAutocompletion(EmbeddedCli *cli) {
937946
PREPARE_IMPL(cli);
938947

948+
if (!IS_FLAG_SET(impl->flags, CLI_FLAG_AUTOCOMPLETE_ENABLED))
949+
return;
950+
939951
AutocompletedCommand cmd = getAutocompletedCommand(cli, impl->cmdBuffer);
940952

941953
if (cmd.candidateCount == 0) {

‎tests/CliTestRunner.cpp‎

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ void CliTestRunner::runTests() {
2626
testHelp();
2727
}
2828

29-
SECTION("Autocomplete") {
30-
testAutocomplete();
29+
SECTION("Autocomplete enabled") {
30+
testAutocompleteEnabled();
3131
}
3232

3333
SECTION("Escape sequences") {
@@ -46,6 +46,35 @@ void CliTestRunner::runTests() {
4646
}
4747
}
4848

49+
void CliTestRunner::testAutocompleteDisabled() {
50+
embeddedCliProcess(cli);
51+
52+
mock.addCommandBinding("set");
53+
54+
SECTION("Live autocomplete disabled") {
55+
mock.sendStr("s");
56+
57+
embeddedCliProcess(cli);
58+
59+
size_t cursor = 0;
60+
auto lines = mock.getLines(false, &cursor);
61+
62+
REQUIRE(lines.size() == 1);
63+
REQUIRE(lines[0] == "> s");
64+
REQUIRE(cursor == 3);
65+
66+
mock.sendStr("\t");
67+
68+
embeddedCliProcess(cli);
69+
70+
lines = mock.getLines(true, &cursor);
71+
72+
REQUIRE(lines.size() == 1);
73+
REQUIRE(lines[0] == "> set");
74+
REQUIRE(cursor == 6);
75+
}
76+
}
77+
4978
void CliTestRunner::testBase() {
5079
auto &commands = mock.getReceivedCommands();
5180

@@ -179,7 +208,7 @@ void CliTestRunner::testHistory() {
179208

180209
SECTION("When history is present, can navigate") {
181210
std::vector<std::string> cmds = {"command", "get", "reset", "exit"};
182-
for (auto &cmd : cmds) {
211+
for (auto &cmd: cmds) {
183212
mock.sendLine(cmd);
184213
}
185214
embeddedCliProcess(cli);
@@ -203,7 +232,7 @@ void CliTestRunner::testHistory() {
203232

204233
SECTION("Sending command multiple times, doesn't create duplicates") {
205234
std::vector<std::string> cmds = {"command", "get", "command", "command"};
206-
for (auto &cmd : cmds) {
235+
for (auto &cmd: cmds) {
207236
mock.sendLine(cmd);
208237
}
209238
embeddedCliProcess(cli);
@@ -231,7 +260,7 @@ void CliTestRunner::testHistory() {
231260

232261
SECTION("Sending command resets history cursor") {
233262
std::vector<std::string> cmds = {"command", "get"};
234-
for (auto &cmd : cmds) {
263+
for (auto &cmd: cmds) {
235264
mock.sendLine(cmd);
236265
}
237266
embeddedCliProcess(cli);
@@ -258,7 +287,7 @@ void CliTestRunner::testHistory() {
258287
}
259288
}
260289

261-
void CliTestRunner::testAutocomplete() {
290+
void CliTestRunner::testAutocompleteEnabled() {
262291
mock.addCommandBinding("get");
263292
mock.addCommandBinding("set");
264293
mock.addCommandBinding("get-new");

‎tests/CliTestRunner.h‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ class CliTestRunner {
1111

1212
void runTests();
1313

14+
void testAutocompleteDisabled();
15+
1416
private:
1517
EmbeddedCli *cli;
1618
CliMock mock;
@@ -19,7 +21,7 @@ class CliTestRunner {
1921

2022
void testHistory();
2123

22-
void testAutocomplete();
24+
void testAutocompleteEnabled();
2325

2426
void testPrinting();
2527

‎tests/EmbeddedCliTest.cpp‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,18 @@ TEST_CASE("EmbeddedCli. Static allocation", "[cli]") {
5151

5252
embeddedCliFree(cli);
5353
}
54+
55+
56+
TEST_CASE("EmbeddedCli. Disabled autocomplete", "[cli]") {
57+
EmbeddedCliConfig *config = embeddedCliDefaultConfig();
58+
config->enableAutoComplete = false;
59+
EmbeddedCli *cli = embeddedCliNew(config);
60+
61+
REQUIRE(cli != nullptr);
62+
63+
CliTestRunner runner(cli);
64+
65+
runner.testAutocompleteDisabled();
66+
67+
embeddedCliFree(cli);
68+
}

0 commit comments

Comments
 (0)