7#include "absl/strings/str_format.h"
17std::string
Lower(std::string_view text) {
18 std::string out(text);
19 std::transform(out.begin(), out.end(), out.begin(), [](
unsigned char c) {
20 return static_cast<char>(std::tolower(c));
26 return std::isspace(
static_cast<unsigned char>(c)) != 0;
29std::string_view Trim(std::string_view text) {
30 while (!text.empty() && IsSpace(text.front()))
31 text.remove_prefix(1);
32 while (!text.empty() && IsSpace(text.back()))
33 text.remove_suffix(1);
37std::optional<int>
ParseDigits(std::string_view digits,
int base) {
39 if (digits.empty() || digits.size() > 6)
42 for (
char c : digits) {
44 if (c >=
'0' && c <=
'9') {
46 }
else if (base == 16 && c >=
'a' && c <=
'f') {
47 digit = 10 + (c -
'a');
49 if (digit < 0 || digit >= base)
51 value = value * base + digit;
72 const std::string lower = Lower(Trim(token));
73 std::string_view text(lower);
76 if (text.front() ==
'#')
77 return ParseDigits(text.substr(1), 10);
78 if (text.front() ==
'$')
79 return ParseDigits(text.substr(1), 16);
80 if (text.size() > 2 && text.substr(0, 2) ==
"0x")
81 return ParseDigits(text.substr(2), 16);
82 if (text.size() > 1 && text.back() ==
'h')
83 return ParseDigits(text.substr(0, text.size() - 1), 16);
84 return ParseDigits(text, 16);
120 std::string lower = Lower(Trim(query));
121 std::string_view text(lower);
122 for (
const char* prefix : {
"go to ",
"goto ",
"go "}) {
123 const std::string_view p(prefix);
124 if (text.substr(0, p.size()) == p) {
125 text = Trim(text.substr(p.size()));
132 while (word_end < text.size() &&
133 std::isalpha(
static_cast<unsigned char>(text[word_end]))) {
136 const std::string_view word = text.substr(0, word_end);
137 const KeywordInfo* keyword =
nullptr;
138 for (
const auto& info : kKeywords) {
139 if (word == info.word) {
149 std::string_view rest = text.substr(word_end);
150 const bool query_has_trailing_space =
151 !query.empty() && IsSpace(query.back()) && rest.empty();
152 if (rest.empty() && !query_has_trailing_space)
154 if (!rest.empty() && rest.front() !=
':' && !IsSpace(rest.front()))
156 if (!rest.empty() && rest.front() ==
':')
157 rest.remove_prefix(1);
161 result.
kind = keyword->kind;
166 for (
char c : rest) {
185 const int width = max_id > 0xFF ? 3 : 2;
188 entry.
name = absl::StrFormat(
"Go to %s …", kind_name);
190 entry.
note = absl::StrFormat(
191 "Type an id: 4A, 0x4A, $4A or 4Ah (hex), #74 (decimal). Range "
193 width, 0, width, max_id);
197 entry.
name = absl::StrFormat(
"Go to %s 0x%0*X", kind_name, width, query.
id);
199 entry.
note = absl::StrFormat(
"Out of range: %s ids are 0x%0*X-0x%0*X",
200 kind_name, width, 0, width, max_id);
205 switch (query.
kind) {
220 ? absl::StrFormat(
"Go to %s 0x%0*X", kind_name, width, query.
id)
221 : absl::StrFormat(
"Go to %s 0x%0*X — %s", kind_name, width, query.
id,
223 entry.
description = absl::StrFormat(
"Jump to %s 0x%0*X (%d)", kind_name,
224 width, query.
id, query.
id);
228 entry.
note =
"No sprite jump path yet; open the Sprite editor manually";
232 const int id = query.
id;
233 switch (query.
kind) {
235 entry.
callback = [id, session_id]() {
241 entry.
callback = [id, session_id]() {
247 entry.
callback = [id, session_id]() {
::yaze::EventBus * event_bus()
Get the current EventBus instance.
std::string Lower(std::string_view text)
constexpr KeywordInfo kKeywords[]
std::optional< int > ParseDigits(std::string_view digits, int base)
CommandEntry BuildGotoEntry(const GotoQuery &query, size_t session_id)
const char * GotoKindName(GotoKind kind)
bool GotoKindHasJumpPath(GotoKind kind)
True when a jump path exists for kind (sprites have none yet).
std::optional< int > ParseGotoId(std::string_view token)
Parse a single id token using the formats above. nullopt if malformed.
int GotoMaxId(GotoKind kind)
Inclusive upper bound for kind.
std::optional< GotoQuery > ParseGotoQuery(std::string_view query)
std::string GetSpriteLabel(int id)
Convenience function to get a sprite label.
std::string GetRoomLabel(int id)
Convenience function to get a room label.
constexpr int kNumOverworldMaps
std::string GetOverworldMapLabel(int id)
Convenience function to get an overworld map label.
static constexpr const char * kNavigation
std::function< void()> callback
static JumpToMapRequestEvent Create(int map, size_t session=0)
static JumpToMessageRequestEvent Create(int message, size_t session=0)
static JumpToRoomRequestEvent Create(int room, size_t session=0)