yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
command_handler.cc
Go to the documentation of this file.
2
3#include <iostream>
4#include <optional>
5#include <utility>
6
7#include "absl/flags/declare.h"
8#include "absl/flags/flag.h"
9#include "absl/strings/str_format.h"
11#include "util/macro.h"
12
13ABSL_DECLARE_FLAG(bool, sandbox);
14
15namespace yaze {
16namespace cli {
17namespace resources {
18namespace {
19
20absl::StatusOr<std::filesystem::path> CaptureRomPathIdentity(
21 const std::filesystem::path& path) {
22 std::error_code absolute_ec;
23 const std::filesystem::path absolute =
24 std::filesystem::absolute(path, absolute_ec).lexically_normal();
25 if (absolute_ec) {
26 return absl::FailedPreconditionError(
27 absl::StrFormat("Cannot capture ROM path identity for %s: %s",
28 path.string(), absolute_ec.message()));
29 }
30
31 std::error_code canonical_ec;
32 const std::filesystem::path canonical =
33 std::filesystem::weakly_canonical(absolute, canonical_ec);
34 if (canonical_ec) {
35 return absl::FailedPreconditionError(
36 absl::StrFormat("Cannot capture ROM path identity for %s: %s",
37 absolute.string(), canonical_ec.message()));
38 }
39 return canonical.lexically_normal();
40}
41
42} // namespace
43
44absl::Status CommandHandler::Run(const std::vector<std::string>& args,
45 Rom* rom_context,
46 std::string* captured_output) {
47 // 1. Parse arguments
48 ArgumentParser parser(args);
49
50 // 2. Validate arguments
51 auto validation_status = ValidateArgs(parser);
52 if (!validation_status.ok()) {
53 std::cerr << "Error: " << validation_status.message() << "\n\n";
54 std::cerr << "Usage: " << GetUsage() << "\n";
55 return validation_status;
56 }
57
58 // 3. Get format string (output format). Some commands reuse --format for
59 // data formatting (hex/ascii/both). If so, fall back to default output.
60 std::string format_str =
61 parser.GetString("format").value_or(GetDefaultFormat());
62
63 // 4. Create output formatter
64 auto formatter_or = OutputFormatter::FromString(format_str);
65 if (!formatter_or.ok()) {
66 if (format_str == "hex" || format_str == "ascii" || format_str == "both" ||
67 format_str == "binary") {
69 } else {
70 return formatter_or.status();
71 }
72 }
73 OutputFormatter formatter = std::move(formatter_or.value());
74
75 // 5. Setup command context
77 config.external_rom_context = rom_context;
78 config.format = format_str;
79 config.verbose = parser.HasFlag("verbose");
80
81 // Check for --rom override
82 if (auto rom_path = parser.GetString("rom"); rom_path.has_value()) {
83 config.rom_path = *rom_path;
84 }
85
86 // Check for --symbols override
87 if (auto symbols_path = parser.GetString("symbols");
88 symbols_path.has_value()) {
89 config.symbols_path = *symbols_path;
90 }
91
92 // Optional project runtime context used to mirror editor feature/custom object
93 // behavior during CLI execution.
94 if (auto project_path = parser.GetString("project-context");
95 project_path.has_value()) {
96 config.project_context_path = *project_path;
97 }
98
99 // Check for --mock-rom flag
100 config.use_mock_rom = parser.HasFlag("mock-rom");
101
102 CommandContext context(config);
103
104 // 6. Get ROM (loads if needed) - only if command requires it
105 Rom* rom = nullptr;
106 std::optional<Rom> sandbox_rom;
107 bool sandbox_enabled = false;
108 CommandInvocationContext invocation_context;
109
110 // Set symbol provider regardless of ROM loading (it might load its own symbols)
112
113 if (RequiresRom()) {
114 ASSIGN_OR_RETURN(rom, context.GetRom());
115 if (!rom->filename().empty()) {
117 const auto rom_path_identity,
118 CaptureRomPathIdentity(std::filesystem::path(rom->filename())));
119 invocation_context.source_rom_path = rom_path_identity;
120 invocation_context.active_rom_path = rom_path_identity;
121 }
122 SetRomContext(rom);
124
125 if (absl::GetFlag(FLAGS_sandbox) || parser.HasFlag("sandbox")) {
126 sandbox_enabled = true;
127 auto sandbox_or =
129 if (!sandbox_or.ok()) {
130 return sandbox_or.status();
131 }
132 invocation_context.sandbox_enabled = true;
133 if (!invocation_context.source_rom_path.has_value()) {
134 ASSIGN_OR_RETURN(invocation_context.source_rom_path,
135 CaptureRomPathIdentity(
136 std::filesystem::path(sandbox_or->source_rom)));
137 }
138 ASSIGN_OR_RETURN(invocation_context.active_rom_path,
139 CaptureRomPathIdentity(sandbox_or->rom_path));
140 sandbox_rom.emplace();
141 auto load_status =
142 sandbox_rom->LoadFromFile(sandbox_or->rom_path.string());
143 if (!load_status.ok()) {
144 return load_status;
145 }
146 rom = &*sandbox_rom;
147 SetRomContext(rom);
148 }
149
150 // 7. Ensure labels are loaded if required
151 if (RequiresLabels()) {
153 }
154 }
155
156 // 8. Begin output formatting
157 formatter.BeginObject(GetOutputTitle());
158
159 // 9. Execute command business logic
160 auto execute_status =
161 ExecuteWithContext(rom, parser, formatter, invocation_context);
162 if (!execute_status.ok()) {
163 // Preserve structured output for failing commands so callers can inspect
164 // machine-readable diagnostics even when status is non-OK.
165 formatter.EndObject();
166 if (captured_output) {
167 *captured_output = formatter.GetOutput();
168 } else {
169 formatter.Print();
170 }
171 return execute_status;
172 }
173
174 if (sandbox_enabled && rom != nullptr && rom->dirty()) {
175 auto save_status = rom->SaveToFile({.save_new = false});
176 if (!save_status.ok()) {
177 return save_status;
178 }
179 }
180
181 // 10. Finalize and print output
182 formatter.EndObject();
183
184 if (captured_output) {
185 *captured_output = formatter.GetOutput();
186 } else {
187 formatter.Print();
188 }
189
190 return absl::OkStatus();
191}
192
194 Descriptor descriptor;
195 descriptor.display_name = GetName(); // Use GetName() for display.
196 descriptor.summary = "Command summary not provided.";
197 descriptor.todo_reference = "todo#unassigned";
198 return descriptor;
199}
200
201} // namespace resources
202} // namespace cli
203} // namespace yaze
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:28
auto filename() const
Definition rom.h:157
absl::Status SaveToFile(const SaveSettings &settings)
Definition rom.cc:371
bool dirty() const
Definition rom.h:145
absl::StatusOr< SandboxMetadata > CreateSandbox(Rom &rom, absl::string_view description)
static RomSandboxManager & Instance()
Utility for parsing common CLI argument patterns.
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.
Encapsulates common context for CLI command execution.
absl::StatusOr< Rom * > GetRom()
Get the ROM instance (loads if not already loaded)
absl::Status EnsureLabelsLoaded(Rom *rom)
Ensure resource labels are loaded.
project::YazeProject * GetProjectContext()
Returns loaded project context when –project-context was used.
emu::debug::SymbolProvider * GetSymbolProvider()
Get the SymbolProvider instance.
virtual bool RequiresLabels() const
Check if the command requires ROM labels.
virtual std::string GetUsage() const =0
Get the command usage string.
virtual std::string GetName() const =0
Get the command name.
virtual void SetRomContext(Rom *rom)
Set the ROM context for tools that need ROM access. Default implementation stores the ROM pointer for...
virtual void SetSymbolProvider(emu::debug::SymbolProvider *provider)
Set the SymbolProvider context.
absl::Status Run(const std::vector< std::string > &args, Rom *rom_context, std::string *captured_output=nullptr)
Execute the command.
virtual std::string GetOutputTitle() const
Get the output title for formatting.
virtual std::string GetDefaultFormat() const
Get the default output format ("json" or "text")
virtual bool RequiresRom() const
Check if the command requires a loaded ROM.
virtual void SetProjectContext(project::YazeProject *project)
Set the YazeProject context. Default implementation does nothing, override if tool needs project info...
virtual Descriptor Describe() const
Provide metadata for TUI/help summaries.
virtual absl::Status ExecuteWithContext(Rom *rom, const ArgumentParser &parser, OutputFormatter &formatter, const CommandInvocationContext &invocation_context)
Execute with immutable, invocation-scoped ROM path identity.
virtual absl::Status ValidateArgs(const ArgumentParser &parser)=0
Validate command arguments.
Utility for consistent output formatting across commands.
std::string GetOutput() const
Get the formatted output.
static absl::StatusOr< OutputFormatter > FromString(const std::string &format)
Create formatter from string ("json" or "text")
void BeginObject(const std::string &title="")
Start a JSON object or text section.
void EndObject()
End a JSON object or text section.
void Print() const
Print the formatted output to stdout.
ABSL_DECLARE_FLAG(bool, sandbox)
#define ASSIGN_OR_RETURN(type_variable_name, expression)
Definition macro.h:62
absl::StatusOr< std::filesystem::path > CaptureRomPathIdentity(const std::filesystem::path &path)
#define RETURN_IF_ERROR(expr)
Definition snes.cc:22
Configuration for command context.
std::optional< std::string > project_context_path
std::optional< std::string > symbols_path
std::optional< std::filesystem::path > active_rom_path
std::optional< std::filesystem::path > source_rom_path