7#include "absl/flags/declare.h"
8#include "absl/flags/flag.h"
9#include "absl/strings/ascii.h"
10#include "absl/strings/match.h"
11#include "absl/strings/str_format.h"
12#include "absl/strings/str_join.h"
20using yaze::cli::util::ParseHexString;
31constexpr int kTrackCustomObjectId = 0x31;
39 std::string* warning) {
40 if (project ==
nullptr) {
51 const auto& defaults =
53 kTrackCustomObjectId);
54 if (defaults.empty()) {
59 if (warning !=
nullptr) {
60 *warning = absl::StrFormat(
61 "project context defines custom_objects_folder but is missing "
62 "custom_object_files[0x%02X]. Seeded default mapping (%d entries); "
63 "save project to persist.",
64 kTrackCustomObjectId,
static_cast<int>(defaults.size()));
83 return absl::OkStatus();
89 : absl::GetFlag(FLAGS_rom);
100 }
else if (!rom_path.empty()) {
103 return absl::FailedPreconditionError(absl::StrFormat(
104 "Failed to load ROM from '%s': %s", rom_path, status.message()));
110 return absl::FailedPreconditionError(
111 "No ROM loaded. Use --rom=<path> or --mock-rom for testing.");
115 if (!project_status.ok()) {
116 return project_status;
120 std::string symbols_path =
122 if (symbols_path.empty() && !rom_path.empty()) {
124 std::string base = rom_path;
125 size_t last_dot = base.find_last_of(
'.');
126 if (last_dot != std::string::npos) {
127 base = base.substr(0, last_dot);
131 std::vector<std::string> exts = {
".mlb",
".sfc.mlb",
".sym",
".cpu.sym",
133 for (
const auto& ext : exts) {
134 std::string path = base + ext;
135 if (std::ifstream(path).good()) {
143 }
else if (!symbols_path.empty()) {
146 std::cerr <<
"Warning: Failed to load symbols from " << symbols_path
147 <<
": " << sym_status.message() << std::endl;
152 return absl::OkStatus();
164 return absl::FailedPreconditionError(
"ROM not loaded");
179 return absl::FailedPreconditionError(
"ROM has no resource label manager");
188 if (labels_status.ok()) {
192 return labels_status;
196 return absl::OkStatus();
201 return absl::OkStatus();
204 return absl::OkStatus();
207 return absl::InvalidArgumentError(
"--project-context cannot be empty");
215 if (!open_status.ok()) {
217 return absl::FailedPreconditionError(
218 absl::StrFormat(
"Failed to open project context '%s': %s",
224 if (ProjectUsesCustomObjects(project) &&
229 <<
"Warning: project context has custom object data but "
230 "kEnableCustomObjects was disabled. Enabling for this command.\n";
233 std::string legacy_mapping_warning;
234 if (SeedLegacyTrackObjectMapping(&project, &legacy_mapping_warning) &&
236 std::cerr <<
"Warning: " << legacy_mapping_warning <<
'\n';
248 active_project.InitializeResourceLabelProvider();
252 if (!active_project.custom_object_files.empty()) {
254 active_project.custom_object_files);
259 if (!active_project.custom_objects_folder.empty()) {
261 active_project.GetAbsolutePath(active_project.custom_objects_folder));
268 active_project.dungeon_tile_patterns.empty()
270 : active_project.GetAbsolutePath(
271 active_project.dungeon_tile_patterns));
276 if (!patterns.ok()) {
278 return patterns.status();
280 return absl::OkStatus();
317 const std::string& name)
const {
318 std::string flag =
"--" + name;
319 std::string equals_form = flag +
"=";
321 for (
size_t i = 0; i <
args_.size(); ++i) {
322 const std::string& arg =
args_[i];
325 if (absl::StartsWith(arg, equals_form)) {
326 return arg.substr(equals_form.length());
330 if (arg == flag && i + 1 <
args_.size()) {
339 const std::string& name)
const {
345 if (!value.has_value()) {
346 return absl::NotFoundError(
347 absl::StrFormat(
"Argument '--%s' not found", name));
351 if (absl::StartsWith(*value,
"0x") || absl::StartsWith(*value,
"0X")) {
353 if (ParseHexString(value->substr(2), &result)) {
356 return absl::InvalidArgumentError(
357 absl::StrFormat(
"Invalid hex integer for '--%s': %s", name, *value));
362 if (absl::SimpleAtoi(*value, &result)) {
366 return absl::InvalidArgumentError(
367 absl::StrFormat(
"Invalid integer for '--%s': %s", name, *value));
372 if (!value.has_value()) {
373 return absl::NotFoundError(
374 absl::StrFormat(
"Argument '--%s' not found", name));
378 std::string hex_str = *value;
379 if (absl::StartsWith(hex_str,
"0x") || absl::StartsWith(hex_str,
"0X")) {
380 hex_str = hex_str.substr(2);
384 if (ParseHexString(hex_str, &result)) {
388 return absl::InvalidArgumentError(
389 absl::StrFormat(
"Invalid hex value for '--%s': %s", name, *value));
393 std::string flag =
"--" + name;
394 for (
const auto& arg :
args_) {
403 std::vector<std::string> positional;
404 for (
size_t i = 0; i <
args_.size(); ++i) {
405 const std::string& arg =
args_[i];
406 if (!absl::StartsWith(arg,
"--")) {
407 positional.push_back(arg);
408 }
else if (arg.find(
'=') == std::string::npos && i + 1 <
args_.size()) {
417 const std::vector<std::string>& required)
const {
418 std::vector<std::string> missing;
419 for (
const auto& arg : required) {
421 missing.push_back(
"--" + arg);
425 if (!missing.empty()) {
426 return absl::InvalidArgumentError(absl::StrFormat(
427 "Missing required arguments: %s", absl::StrJoin(missing,
", ")));
430 return absl::OkStatus();
438 const std::string& format) {
439 std::string lower = absl::AsciiStrToLower(format);
440 if (lower ==
"json") {
442 }
else if (lower ==
"text" || lower ==
"table") {
446 return absl::InvalidArgumentError(absl::StrFormat(
447 "Unknown format: %s (expected 'json', 'text' or 'table')", format));
465 }
else if (
IsText() && !title.empty()) {
466 buffer_ += absl::StrFormat(
"=== %s ===\n", title);
492 const std::string& value) {
497 buffer_ += absl::StrFormat(
" %-20s : %s\n", key, value);
502 AddField(key, value !=
nullptr ? std::string(value) : std::string());
508 buffer_ += absl::StrFormat(
"%d", value);
510 buffer_ += absl::StrFormat(
" %-20s : %d\n", key, value);
517 buffer_ += absl::StrFormat(
"%llu", value);
519 buffer_ += absl::StrFormat(
" %-20s : %llu\n", key, value);
526 buffer_ += value ?
"true" :
"false";
528 buffer_ += absl::StrFormat(
" %-20s : %s\n", key, value ?
"yes" :
"no");
536 buffer_ += absl::StrFormat(
"\"0x%0*X\"", width, value);
538 buffer_ += absl::StrFormat(
" %-20s : 0x%0*X\n", key, width, value);
557 buffer_ += absl::StrFormat(
" %s:\n", key);
566 const int item_count =
json_stack_.back().item_count;
569 if (item_count == 0) {
587 buffer_ += absl::StrFormat(
" - %s\n", item);
592 const std::string& json) {
629 if (context.item_count > 0) {
633 ++context.item_count;
641 if (!context.first) {
644 context.first =
false;
653 result.reserve(str.size() + 10);
679 if (
static_cast<unsigned char>(c) < 0x20) {
680 result += absl::StrFormat(
"\\u%04x",
static_cast<int>(c));
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
project::ResourceLabelManager * resource_label()
absl::Status LoadFromFile(const std::string &filename, const LoadOptions &options=LoadOptions::Defaults())
std::optional< std::string > FindArgValue(const std::string &name) const
std::vector< std::string > args_
ArgumentParser(const std::vector< std::string > &args)
std::vector< std::string > GetPositional() const
Get all remaining positional arguments.
std::optional< std::string > GetString(const std::string &name) const
Parse a named argument (e.g., –format=json or –format json)
bool HasFlag(const std::string &name) const
Check if a flag is present.
absl::Status RequireArgs(const std::vector< std::string > &required) const
Validate that required arguments are present.
absl::StatusOr< int > GetHex(const std::string &name) const
Parse a hex integer argument.
absl::StatusOr< int > GetInt(const std::string &name) const
Parse an integer argument (supports hex with 0x prefix)
std::optional< project::YazeProject > loaded_project_
absl::StatusOr< Rom * > GetRom()
Get the ROM instance (loads if not already loaded)
void RestoreProjectRuntimeContext()
absl::Status EnsureLabelsLoaded(Rom *rom)
Ensure resource labels are loaded.
emu::debug::SymbolProvider * GetSymbolProvider()
Get the SymbolProvider instance.
std::optional< core::FeatureFlags::Flags > previous_feature_flags_
std::optional< zelda3::CustomObjectManager::State > previous_custom_object_state_
bool project_runtime_applied_
emu::debug::SymbolProvider symbol_provider_
absl::Status ApplyProjectRuntimeContext()
absl::Status Initialize()
Initialize the context and load ROM if needed.
std::optional< zelda3::ResourceLabelProvider::State > previous_label_state_
CommandContext(const Config &config)
Provider for symbol (label) resolution in disassembly.
bool HasSymbols() const
Check if any symbols are loaded.
absl::Status LoadSymbolFile(const std::string &path, SymbolFormat format=SymbolFormat::kAuto)
Load symbols from a .sym file (various formats)
void RestoreState(const State &state)
static const std::vector< std::string > & DefaultSubtypeFilenamesForObject(int object_id)
void SetObjectFileMap(const std::unordered_map< int, std::vector< std::string > > &map)
static CustomObjectManager & Get()
void SetTilePatternsSource(const std::string &path)
void Initialize(const std::string &custom_objects_folder)
absl::StatusOr< std::shared_ptr< const DungeonTilePatterns > > GetTilePatterns()
void ClearObjectFileMap()
State SnapshotState() const
void RefreshFeatureFlagMappings()
static DrawRoutineRegistry & Get()
void RestoreState(const State &state)
State SnapshotState() const
ABSL_DECLARE_FLAG(std::string, rom)
absl::Status InitializeMockRom(Rom &rom)
Initialize a mock ROM for testing without requiring an actual ROM file.
ResourceLabelProvider & GetResourceLabels()
Get the global ResourceLabelProvider instance.
Configuration for command context.
std::optional< std::string > project_context_path
std::optional< std::string > symbols_path
std::optional< std::string > rom_path
Rom * external_rom_context
bool kEnableCustomObjects
std::unordered_map< std::string, std::unordered_map< std::string, std::string > > labels_
Modern project structure with comprehensive settings consolidation.
std::unordered_map< int, std::vector< std::string > > custom_object_files
std::string custom_objects_folder
std::unordered_map< std::string, std::unordered_map< std::string, std::string > > resource_labels
absl::Status InitializeEmbeddedLabels(const std::unordered_map< std::string, std::unordered_map< std::string, std::string > > &labels)
absl::Status Open(const std::string &project_path)
core::FeatureFlags::Flags feature_flags
static std::unordered_map< std::string, std::unordered_map< std::string, std::string > > ToResourceLabels()
Convert all labels to a structured map for project embedding.