Shell: Tab completes every word of a command, and * and ? stand for several files (#67)
CI / build (pull_request) Successful in 1m38s
Site / build (pull_request) Successful in 9s

Tab used to complete a command's first word only. It now follows the help
text word by word: `lora st` gives `lora status`, `gnss track ` lists
`start  stop`. The words are read from the help text as written, so a new
command completes with no table to keep; the Shell's own words are added in
the same notation.

`*` and `?` in the last part of a path, for ls, du, rm, cp and mv, from the
Shell and both consoles. The command runs once for each name matched, lined
up and run by the main loop as each finishes; `cancel` empties the line-up.
64 matches at most, refused whole past that. In the Shell, rm with a pattern
asks once, with the count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
2026-10-07 12:47:10 +02:00
co-authored by Claude Opus 5.5
parent d17d10948d
commit 0fdbb5b1ed
16 changed files with 368 additions and 112 deletions
+11 -8
View File
@@ -34,14 +34,17 @@ class ShellLog {
uint32_t revision_ = 0;
};
// The commands `help` lists: the first word of each (`ls [folder] | du <path>` gives ls and du),
// each once, in the order they appear.
std::vector<std::string> commandWords(const char* helpText);
// Tab: `typed` with its first word completed as far as the commands agree. Unchanged when the cursor
// is past the first word, or when nothing starts with it. `matches` gets what it could become, when
// there is more than one.
std::string completeCommand(const std::string& typed, const std::vector<std::string>& words, std::vector<std::string>& matches);
// Tab on a command (issue #67): every word of it, read from the firmware's `help` text each time it
// is asked, so nothing is kept in memory for it. A line of that text is commands, three spaces, then
// what they do; commands are separated by " | ", a word like on|off is either of them, and a command
// stops being words at its first <argument>, [option] or "...":
// lora rx on|off | lora preset <name> the radio
// gives "lora rx on", "lora rx off" and "lora preset". An App's name starts with a capital.
//
// The line with its last word completed as far as the commands that fit agree; a word completed
// whole gets a space after it. `matches` gets the candidates when there are several. Unchanged, with
// no matches, when no command goes on that way: then it may be a path (below).
std::string completeWords(const std::string& typed, const char* helpText, std::vector<std::string>& matches);
// Tab on a later word: a path on the SD card (issue #67). What is being completed, taken apart:
// `rm -r /notes/sh` is head "rm -r ", folder "/notes/", prefix "sh". False when the cursor is still