Skip to content

Commit e150a9d

Browse files
committed
Add expanded documentation
1 parent f5db4ba commit e150a9d

9 files changed

Lines changed: 933 additions & 0 deletions

File tree

docs/_index.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
+++
2+
title = "TinyCLI"
3+
description = "A tiny command-line interface for embedded systems"
4+
sort_by = "weight"
5+
+++
6+
7+
_TinyCLI_ is a tiny _command-line interface_ library for embedded systems. It allows you to register a set of commands (and optionally users), and then by directing input and output you automatically get a command-line interface with tab-completion, history, [shortcut support](@/shortcuts.md), [pattern matching](@/pattern-matching.md), etc.
8+
It can also coexist with log or debug-output.
9+
10+
It is written in C, performs no dynamic allocations, and is intended to run on microcontrollers with or without an RTOS. Typical applications include providing a CLI over a serial line or a [Telnet connection](@/telnet.md).
11+
12+
![TinyCLI in action](/sample.gif)
13+
14+
The library is [configured](@/configuration.md) using compiler flags, and features can be deactivated to reduce memory usage to fit on memory-constrained systems.
15+
16+
The library is provided in two layers. Unless you have very specific requirements it is recommended to only use the high-level `tclie` API:
17+
18+
- [`tcli`](@/tcli.md): The lower-level core. Input characters are fed in, and the line buffer, command history, tab-completion, and output callback are managed internally. When the user presses {{ kbd(key="Enter") }}, the registered exec callback is invoked with an `argc`/`argv`-style argument list.
19+
20+
- [`tclie`](@/tclie.md): A thin wrapper on top of `tcli` that adds a registered command table, optional users with login, an optional pattern-matching system for argument validation and automatic tab-completion, and the built-in commands `help`, `clear`, `login`, and `logout`.
21+
22+
Prompt rendering, history, tab-completion, and prompt-preserving log output are common to both layers.
23+
24+
## Quick-Start
25+
26+
Below is a minimal program that shows how to use the library:
27+
28+
```c
29+
#include <stdio.h>
30+
#include "tclie.h"
31+
32+
/* Output callback. The library routes every emitted byte through this;
33+
on an MCU this would typically write to a UART instead of stdout. */
34+
void out(void *arg, const char *str)
35+
{
36+
printf("%s", str);
37+
}
38+
39+
/* Command callback for "echo ...". */
40+
int cmd_echo(void *arg, int argc, const char **argv)
41+
{
42+
for (int i = 1; i < argc; i++)
43+
printf("%s%s", argv[i], i + 1 < argc ? " " : "\n");
44+
return 0;
45+
}
46+
47+
/* Command table. The descriptions are printed by the built-in help command. */
48+
static const tclie_cmd_t cmds[] = {
49+
{ .name = "echo", .fn = cmd_echo, .desc = "Print arguments back" },
50+
};
51+
52+
int main(void)
53+
{
54+
/* Initialize and register command table. */
55+
tclie_t t;
56+
tclie_init(&t, out, NULL);
57+
tclie_reg_cmds(&t, cmds, sizeof(cmds) / sizeof(*cmds));
58+
59+
/* Feed input characters. */
60+
int c;
61+
while ((c = getchar()) != EOF)
62+
tclie_in_char(&t, (char) c);
63+
}
64+
```
65+
66+
## Documentation
67+
68+
- [Getting Started](@/getting-started.md): a longer walkthrough with prompts, output, and a SIGINT handler.
69+
- [The `tcli` Core](@/tcli.md): basic features and usage for finer control (e.g. writing a custom command dispatch or using TinyCLI without the wrapper).
70+
- [The `tclie` Wrapper](@/tclie.md): command tables, users, and the built-in commands.
71+
- [Pattern Matching](@/pattern-matching.md): argument-shape validation and context-aware tab-completion.
72+
- [Logging and Output](@/logging.md): printing without disturbing the prompt.
73+
- [Keyboard Shortcuts](@/shortcuts.md): the full readline-style shortcut table.
74+
- [Configuration](@/configuration.md): compile-time configuration and ANSI color macros for prompt customization.
75+
- [Telnet Integration](@/telnet.md): option negotiation for a clean Telnet prompt.
76+
77+
## Examples
78+
79+
The [examples directory](https://github.com/dpse/tcli/tree/master/examples) contains:
80+
81+
- [Linux CLI](https://github.com/dpse/tcli/tree/master/examples/linux): full terminal integration with termios, history, signal handling, and a periodic logging demo.
82+
- [Arduino](https://github.com/dpse/tcli/tree/master/examples/arduino): serial CLI for AVR, <abbr>ESP32</abbr>, and <abbr>RP2040</abbr> via PlatformIO, with memory-tight defaults.
83+
- [Shared command set](https://github.com/dpse/tcli/blob/master/examples/common/example_cmds.h): patterns, options, login, and subcommands, reused across platforms.

docs/configuration.md

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
+++
2+
title = "Configuration"
3+
description = "Compile-time #defines and the bundled ANSI macros"
4+
weight = 60
5+
+++
6+
7+
All tuning is performed via compile-time `#define`s; no runtime configuration is provided. A default can be overridden by defining the corresponding macro before including the header, or by passing `-D...` to the compiler.
8+
9+
## Line Buffer and Tokens
10+
11+
| Macro | Default | Effect |
12+
|------------------------|---------|--------|
13+
| `TCLI_CMDLINE_MAX_LEN` | `64` | Maximum number of characters that fit on the command line (excluding the null terminator). The full buffer is embedded in `tcli_t`, so this value directly affects the struct size. |
14+
| `TCLI_MAX_TOKENS` | `12` | Maximum number of whitespace-separated tokens produced by the tokenizer. Lines with more tokens are rejected before the executor is invoked. |
15+
16+
## History
17+
18+
| Macro | Default | Effect |
19+
|-----------------------|---------|--------|
20+
| `TCLI_HISTORY_BUF_LEN`| `512` | Size of the ring buffer that stores history lines. Setting it to `0` compiles history out entirely: no {{ kbd(key="Up") }}/{{ kbd(key="Down") }}, no {{ kbd(key="Ctrl+r") }}, smaller `tcli_t`. |
21+
22+
## Output Buffering
23+
24+
| Macro | Default | Effect |
25+
|-----------------------|---------|--------|
26+
| `TCLI_OUTPUT_BUF_LEN` | `256` | Size of the buffer used to coalesce `tcli_out` writes before they reach the output callback. Setting it to `0` disables buffering; every byte is forwarded to the callback immediately. |
27+
28+
## Tab-Completion
29+
30+
| Macro | Default | Effect |
31+
|-----------------|---------|--------|
32+
| `TCLI_COMPLETE` | `1` | Setting to `0` compiles out tab-completion entirely (smaller binary, `tcli_compl_fn_t` removed). |
33+
34+
## Default Prompts
35+
36+
Each prompt is a string. The defaults wrap the visible text in ANSI color escapes; the same form can be used in custom prompts to retain coloring.
37+
38+
| Macro | Default | Rendered |
39+
|---|---|---|
40+
| `TCLI_DEFAULT_PROMPT` | `(TCLI_COLOR_GREEN "> " TCLI_COLOR_DEFAULT)` | <code style="background:#000000;color:#00bb00">&gt;&nbsp;</code> |
41+
| `TCLI_DEFAULT_ERROR_PROMPT` | `(TCLI_COLOR_RED "> " TCLI_COLOR_DEFAULT)` | <code style="background:#000000;color:#bb0000">&gt;&nbsp;</code> |
42+
| `TCLI_DEFAULT_SEARCH_PROMPT` | `(TCLI_COLOR_GREEN "? " TCLI_COLOR_DEFAULT)` | <code style="background:#000000;color:#00bb00">?&nbsp;</code> |
43+
44+
These are the starting values. The prompts can also be overridden at runtime via [`tcli_set_prompt`](@/tcli.md#prompts) and the corresponding setters.
45+
46+
## `tclie`-Specific
47+
48+
| Macro | Default | Effect |
49+
|--------------------------------|---------|--------|
50+
| `TCLIE_ENABLE_USERS` | `1` | Compiles in users and login. Set to `0` for command-only CLIs. |
51+
| `TCLIE_ENABLE_USERNAMES` | `1` | Enables usernames in addition to passwords. Set to `0` for password-only login (matched against any user). |
52+
| `TCLIE_LOGIN_ATTEMPTS` | `3` | Number of incorrect password attempts before the login is rejected. |
53+
| `TCLIE_PATTERN_MATCH` | `1` | Compiles in [pattern matching](@/pattern-matching.md). Set to `0` to reduce footprint when not used. |
54+
| `TCLIE_PATTERN_MATCH_MAX_TOKENS` | `TCLI_MAX_TOKENS` | Maximum number of tokens considered during pattern matching. More tokens require a deeper stack depth. |
55+
| `TCLIE_PATTERN_MATCH_BUF_LEN` | `64` | Scratch buffer used for pattern-derived tab-completion candidates. |
56+
57+
## ANSI Color and Format Macros
58+
59+
A set of ANSI escape constants is provided for use in prompts and command output. They are referenced by name; the samples below show how each renders in a terminal.
60+
61+
### Foreground Colors
62+
63+
| Macro | Sample |
64+
|---|---|
65+
| `TCLI_COLOR_BLACK` | <code style="background:#000000;color:#000000">Sample</code> |
66+
| `TCLI_COLOR_RED` | <code style="background:#000000;color:#bb0000">Sample</code> |
67+
| `TCLI_COLOR_GREEN` | <code style="background:#000000;color:#00bb00">Sample</code> |
68+
| `TCLI_COLOR_YELLOW` | <code style="background:#000000;color:#bbbb00">Sample</code> |
69+
| `TCLI_COLOR_BLUE` | <code style="background:#000000;color:#0000bb">Sample</code> |
70+
| `TCLI_COLOR_MAGENTA` | <code style="background:#000000;color:#bb00bb">Sample</code> |
71+
| `TCLI_COLOR_CYAN` | <code style="background:#000000;color:#00bbbb">Sample</code> |
72+
| `TCLI_COLOR_WHITE` | <code style="background:#000000;color:#bbbbbb">Sample</code> |
73+
| `TCLI_COLOR_BRIGHT_BLACK` | <code style="background:#000000;color:#555555">Sample</code> |
74+
| `TCLI_COLOR_BRIGHT_RED` | <code style="background:#000000;color:#ff5555">Sample</code> |
75+
| `TCLI_COLOR_BRIGHT_GREEN` | <code style="background:#000000;color:#55ff55">Sample</code> |
76+
| `TCLI_COLOR_BRIGHT_YELLOW` | <code style="background:#000000;color:#ffff55">Sample</code> |
77+
| `TCLI_COLOR_BRIGHT_BLUE` | <code style="background:#000000;color:#5555ff">Sample</code> |
78+
| `TCLI_COLOR_BRIGHT_MAGENTA` | <code style="background:#000000;color:#ff55ff">Sample</code> |
79+
| `TCLI_COLOR_BRIGHT_CYAN` | <code style="background:#000000;color:#55ffff">Sample</code> |
80+
| `TCLI_COLOR_BRIGHT_WHITE` | <code style="background:#000000;color:#ffffff">Sample</code> |
81+
| `TCLI_COLOR_DEFAULT` | Restores the terminal's default foreground color. |
82+
83+
### Background Colors
84+
85+
| Macro | Sample |
86+
|---|---|
87+
| `TCLI_BG_COLOR_BLACK` | <code style="background:#000000;color:#bbbbbb">Sample</code> |
88+
| `TCLI_BG_COLOR_RED` | <code style="background:#bb0000;color:#ffffff">Sample</code> |
89+
| `TCLI_BG_COLOR_GREEN` | <code style="background:#00bb00;color:#ffffff">Sample</code> |
90+
| `TCLI_BG_COLOR_YELLOW` | <code style="background:#bbbb00;color:#000000">Sample</code> |
91+
| `TCLI_BG_COLOR_BLUE` | <code style="background:#0000bb;color:#ffffff">Sample</code> |
92+
| `TCLI_BG_COLOR_MAGENTA` | <code style="background:#bb00bb;color:#ffffff">Sample</code> |
93+
| `TCLI_BG_COLOR_CYAN` | <code style="background:#00bbbb;color:#000000">Sample</code> |
94+
| `TCLI_BG_COLOR_WHITE` | <code style="background:#bbbbbb;color:#000000">Sample</code> |
95+
| `TCLI_BG_COLOR_DEFAULT` | Restores the terminal's default background color. |
96+
97+
### Text Formatting
98+
99+
| Macro | Sample |
100+
|---|---|
101+
| `TCLI_FORMAT_BOLD` | <code style="background:#000000;color:#bbbbbb;font-weight:700">Sample</code> |
102+
| `TCLI_FORMAT_DIM` | <code style="background:#000000;color:#bbbbbb;opacity:0.55">Sample</code> |
103+
| `TCLI_FORMAT_ITALIC` | <code style="background:#000000;color:#bbbbbb;font-style:italic">Sample</code> |
104+
| `TCLI_FORMAT_UNDERLINE` | <code style="background:#000000;color:#bbbbbb;text-decoration:underline">Sample</code> |
105+
| `TCLI_FORMAT_RESET` | Clears all color and formatting. |
106+
107+
### Combinations
108+
109+
Format and color macros concatenate; any number can be combined.
110+
111+
| Macros | Sample |
112+
|---|---|
113+
| `TCLI_FORMAT_BOLD TCLI_COLOR_RED` | <code style="background:#000000;color:#bb0000;font-weight:700">Sample</code> |
114+
| `TCLI_FORMAT_BOLD TCLI_FORMAT_UNDERLINE TCLI_COLOR_CYAN` | <code style="background:#000000;color:#00bbbb;font-weight:700;text-decoration:underline">Sample</code> |
115+
| `TCLI_FORMAT_ITALIC TCLI_COLOR_GREEN` | <code style="background:#000000;color:#00bb00;font-style:italic">Sample</code> |
116+
| `TCLI_FORMAT_DIM TCLI_COLOR_YELLOW` | <code style="background:#000000;color:#bbbb00;opacity:0.55">Sample</code> |
117+
| `TCLI_BG_COLOR_BLUE TCLI_COLOR_BRIGHT_WHITE` | <code style="background:#0000bb;color:#ffffff">Sample</code> |
118+
| `TCLI_FORMAT_BOLD TCLI_BG_COLOR_WHITE TCLI_COLOR_RED` | <code style="background:#bbbbbb;color:#bb0000;font-weight:700">Sample</code> |
119+
120+
The constants concatenate at compile time and can be composed directly into a single string literal:
121+
122+
```c
123+
#define TCLI_DEFAULT_PROMPT \
124+
(TCLI_FORMAT_BOLD TCLI_COLOR_CYAN "device> " TCLI_FORMAT_RESET)
125+
```
126+
127+
The format macros used by `tclie` and the `help` command are also overridable:
128+
129+
| Macro | Default | Rendered |
130+
|---|---|---|
131+
| `TCLIE_SUCCESS_FORMAT` | `TCLI_COLOR_GREEN` | <code style="background:#000000;color:#00bb00">Sample</code> |
132+
| `TCLIE_FAILURE_FORMAT` | `TCLI_COLOR_RED` | <code style="background:#000000;color:#bb0000">Sample</code> |
133+
| `TCLIE_COMMAND_FORMAT` | `(TCLI_FORMAT_BOLD TCLI_FORMAT_UNDERLINE TCLI_COLOR_CYAN)` | <code style="background:#000000;color:#00bbbb;font-weight:700;text-decoration:underline">Sample</code> |
134+
| `TCLIE_USAGE_FORMAT` | `TCLI_COLOR_CYAN` | <code style="background:#000000;color:#00bbbb">Sample</code> |
135+
| `TCLIE_OPTION_FORMAT` | `(TCLI_FORMAT_ITALIC TCLI_COLOR_CYAN)` | <code style="background:#000000;color:#00bbbb;font-style:italic">Sample</code> |
136+
137+
Setting any of these to an empty string removes the corresponding color or formatting from the help output, e.g. for log capture or terminals that do not render escape sequences.
138+
139+
The tab-completion display has two further format macros:
140+
141+
| Macro | Default | Rendered | Effect |
142+
|---|---|---|---|
143+
| `TCLI_MATCH_FORMAT` | `TCLI_COLOR_BRIGHT_BLACK` | <code style="background:#000000;color:#555555">Sample</code> | Format of the common-prefix match hint shown while completing. |
144+
| `TCLI_SELECTION_FORMAT` | `(TCLI_BG_COLOR_WHITE TCLI_COLOR_BLACK)` | <code style="background:#bbbbbb;color:#000000">Sample</code> | Format of the currently-selected candidate when cycling through matches. |
145+
146+
## Version
147+
148+
The library version is available at compile time through macros defined in `tcli.h`: `TCLI_VERSION_MAJOR`, `TCLI_VERSION_MINOR`, `TCLI_VERSION_PATCH`, and `TCLI_VERSION_STR`.

docs/getting-started.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
+++
2+
title = "Getting Started"
3+
description = "Wire up TinyCLI to a character stream and register a command"
4+
weight = 10
5+
+++
6+
7+
The smallest useful TinyCLI integration consists of reading input characters from some source (e.g. `getchar`, a UART RX, or a [Telnet socket](@/telnet.md)), feeding them to the library, and forwarding the library's output to the corresponding sink.
8+
9+
## 1. Output Callback
10+
11+
TinyCLI does not write anywhere directly. A single callback is provided at initialization and the library routes all output through it: the prompt, echoed input, command output, and formatting escape sequences.
12+
13+
```c
14+
#include <stdio.h>
15+
#include "tclie.h"
16+
17+
void out(void *arg, const char *str)
18+
{
19+
/* arg is the third argument passed to tclie_init. Below we pass &t so
20+
command callbacks can call tclie_out; in production it is more often
21+
a pointer to a UART or socket context, used here as e.g.
22+
uart_write(arg, str) or telnet_send(arg, str). */
23+
printf("%s", str);
24+
}
25+
```
26+
27+
## 2. Command Definitions
28+
29+
A command consists of a name, a callback, and a short description used by the built-in `help` command. The callback receives the conventional `argc`/`argv` pair along with the `arg` value supplied to `tclie_init`.
30+
31+
```c
32+
int cmd_echo(void *arg, int argc, const char **argv)
33+
{
34+
tclie_t *t = arg;
35+
for (int i = 1; i < argc; i++) {
36+
tclie_out(t, argv[i]);
37+
tclie_out(t, i + 1 < argc ? " " : "\n");
38+
}
39+
40+
/* zero = success; non-zero switches the prompt to the error variant */
41+
return 0;
42+
}
43+
44+
int cmd_reboot(void *arg, int argc, const char **argv)
45+
{
46+
tclie_t *t = arg;
47+
tclie_out(t, "rebooting...\n");
48+
/* hardware_reset(); */
49+
return 0;
50+
}
51+
52+
static const tclie_cmd_t cmds[] = {
53+
{ .name = "echo", .fn = cmd_echo, .desc = "Print arguments back" },
54+
{ .name = "reboot", .fn = cmd_reboot, .desc = "Reset the device" },
55+
};
56+
```
57+
58+
Additional fields on `tclie_cmd_t` (`min_user_level`, `pattern`, `options`) are described in [The tclie Wrapper](@/tclie.md) and [Pattern Matching](@/pattern-matching.md). They can be omitted when users and argument validation are not required.
59+
60+
## 3. Initialization and Input
61+
62+
```c
63+
int main(void)
64+
{
65+
tclie_t t;
66+
tclie_init(&t, out, &t);
67+
tclie_reg_cmds(&t, cmds, sizeof(cmds) / sizeof(*cmds));
68+
69+
int c;
70+
while ((c = getchar()) != EOF)
71+
tclie_in_char(&t, (char) c);
72+
73+
return 0;
74+
}
75+
```
76+
77+
The above is a complete CLI with tab-completion and command history. The built-in `help` command lists registered commands, {{ kbd(key="Tab") }} completes partial commands, {{ kbd(key="Up") }}/{{ kbd(key="Down") }} walks the history, and {{ kbd(key="Ctrl+r") }} performs a backwards history search.
78+
79+
## 4. Next Steps
80+
81+
A SIGINT handler can be registered to catch {{ kbd(key="Ctrl+c") }} (see [`tclie_set_sigint`](@/tclie.md#sigint)).
82+
83+
Commands can be restricted to certain user levels by enabling the optional users feature:
84+
85+
```c
86+
static const tclie_user_t users[] = {
87+
{ .name = "admin", .password = "12345", .level = 2 },
88+
};
89+
tclie_reg_users(&t, users, sizeof(users) / sizeof(*users));
90+
```
91+
92+
A command with `min_user_level = 2` then only runs after `login admin` (see [The tclie Wrapper](@/tclie.md#users-and-login)).
93+
94+
Argument shape can be validated with patterns instead of inspecting `argc` manually:
95+
96+
```c
97+
{ .name = "set", .fn = cmd_set, .desc = "Set value", .pattern = "set <key> <value>" }
98+
```
99+
100+
The pattern is also used to drive context-aware tab-completion (see [Pattern Matching](@/pattern-matching.md)).
101+
102+
Log output that does not interfere with the current prompt is provided by `tclie_log` and `tclie_log_printf` (see [Logging and Output](@/logging.md)).

0 commit comments

Comments
 (0)