Public Access
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
59 lines
2.6 KiB
C++
59 lines
2.6 KiB
C++
#pragma once
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace roro::files {
|
|
|
|
// Paths on the SD card are absolute and use '/': "/gemini/saved/index.gmi".
|
|
std::string parentOf(const std::string& path); // "/" for a top-level entry and for "/"
|
|
std::string baseName(const std::string& path); // "" for "/"
|
|
std::string joinPath(const std::string& folder, const std::string& name);
|
|
std::string extensionOf(const std::string& name); // lower case, without the dot; "" if none
|
|
bool isInside(const std::string& path, const std::string& folder); // a folder is inside itself
|
|
|
|
// A name typed for rename or a new folder (F1, Q131): "" if FAT and this App can take it, or why not.
|
|
std::string checkName(const std::string& name);
|
|
|
|
// The top-level folders the firmware keeps its files in. They can't be renamed or deleted;
|
|
// what's in them can (Q130).
|
|
extern const char* const kFirmwareFolders[];
|
|
extern const size_t kFirmwareFolderCount;
|
|
constexpr const char* kGeminiCache = "/gemini/cache";
|
|
|
|
// Why `path` can't be renamed, moved or deleted, or "" if it can (Q130). `inUse`: the files the
|
|
// firmware has open right now.
|
|
std::string whyReadOnly(const std::string& path, const std::vector<std::string>& inUse);
|
|
|
|
// Why `source` can't be copied or moved into the folder `into`, or "" if it can.
|
|
std::string whyNotInto(const std::string& source, const std::string& into);
|
|
|
|
// "a (2).gmi": the name of a copy made next to its original.
|
|
std::string copyName(const std::string& name, int n);
|
|
|
|
// Which viewer opens a file (Q134), from its name. Unknown: look at the first bytes.
|
|
enum class FileKind : uint8_t { Text, Gpx, Pcap, Ota, Unknown };
|
|
FileKind kindOf(const std::string& name);
|
|
bool opensAtEnd(const std::string& name); // logs
|
|
bool looksLikeText(const uint8_t* data, size_t len);
|
|
|
|
// `rm`'s arguments, as Unix has them (issue #67): -r for a folder and what's in it, -f for no
|
|
// question, alone or together (-rf, -fr, -r -f), then the path, which may hold spaces.
|
|
struct RmArgs {
|
|
bool recursive = false, force = false;
|
|
std::string path;
|
|
};
|
|
RmArgs parseRm(const std::string& args);
|
|
|
|
// Patterns in a path (issue #67): * for any run of characters, ? for one, in the last part of the
|
|
// path only (/notes/*.txt, not /*/a.txt). Cases aren't told apart, as on the card.
|
|
bool hasGlob(const std::string& text);
|
|
bool globMatch(const std::string& pattern, const std::string& name);
|
|
// "/notes/*.txt" taken apart: the folder ("/notes", or "/" at the top) and the pattern ("*.txt").
|
|
// False if there's no pattern in it, or if the folder has one too.
|
|
bool splitGlob(const std::string& path, std::string& folder, std::string& pattern);
|
|
|
|
} // namespace roro::files
|