23const std::filesystem::path headers_rel_path = std::filesystem::path{
"src"} /
"data" /
"tilesets" /
"headers.h";
30 std::filesystem::path project_root, gsl::not_null<const TextFormatter *> format)
31 : project_root_{std::move(project_root)}, format_{format}
36 const std::string &tileset_name,
const std::string &new_callback_value)
const
38 return update_fields(tileset_name, {{
"callback", new_callback_value}});
42 const std::string &tileset_name,
const std::map<std::string, std::string> &field_updates)
const
44 if (field_updates.empty()) {
48 const auto headers_path = project_root_ / headers_rel_path;
54 parser.parse_struct_initializers(
"gTileset_"),
56 format_->
format(
"{}: failed to parse tileset headers",
FormatParam{headers_path.string(), Style::bold}));
60 for (
const auto &struct_decl : struct_decls) {
61 if (struct_decl.variable_name() == tileset_name) {
62 target_struct = &struct_decl;
67 if (target_struct ==
nullptr) {
73 std::map<std::string, std::size_t> field_line_indices;
74 for (
const auto &field : target_struct->
fields()) {
75 if (field_updates.contains(field.field_name())) {
76 field_line_indices[field.field_name()] = field.position().line - 1;
81 for (
const auto &field_name : field_updates | std::views::keys) {
82 if (!field_line_indices.contains(field_name)) {
84 "tileset '{}' has no .{} field",
91 std::vector<std::string> file_lines = parser.file_lines();
92 for (
const auto &[field_name, new_value] : field_updates) {
93 const std::size_t line_index = field_line_indices.at(field_name);
94 if (line_index >= file_lines.size()) {
96 ".{} field line {} out of bounds for file with {} lines",
101 file_lines[line_index] =
" ." + field_name +
" = " + new_value +
",";
105 std::ofstream out{headers_path};
106 if (!out.is_open()) {
111 for (
const auto &line : file_lines) {
127 const std::string prefix =
"gTileset_";
128 if (!tileset_name.starts_with(prefix)) {
130 "tileset name '{}' does not start with '{}'",
134 const std::string shorthand = tileset_name.substr(prefix.size());
136 std::map<std::string, std::string> updates{
137 {
"tiles",
"gTilesetTiles_PorytilesManaged_" + shorthand},
138 {
"palettes",
"gTilesetPalettes_PorytilesManaged_" + shorthand},
139 {
"metatiles",
"gMetatiles_PorytilesManaged_" + shorthand},
140 {
"metatileAttributes",
"gMetatileAttributes_PorytilesManaged_" + shorthand}};
149 const std::string prefix =
"gTileset_";
150 if (!tileset_name.starts_with(prefix)) {
152 "tileset name '{}' does not start with '{}'",
156 const std::string shorthand = tileset_name.substr(prefix.size());
158 const auto headers_path = project_root_ / headers_rel_path;
164 parser.parse_struct_initializers(
"gTileset_"),
166 format_->
format(
"{}: failed to parse tileset headers",
FormatParam{headers_path.string(), Style::bold}));
169 for (
const auto &struct_decl : struct_decls) {
170 if (struct_decl.variable_name() == tileset_name) {
177 const std::string is_secondary_value = is_secondary ?
"TRUE" :
"FALSE";
178 const std::string tiles_value =
"gTilesetTiles_PorytilesManaged_" + shorthand;
179 const std::string palettes_value =
"gTilesetPalettes_PorytilesManaged_" + shorthand;
180 const std::string metatiles_value =
"gMetatiles_PorytilesManaged_" + shorthand;
181 const std::string attributes_value =
"gMetatileAttributes_PorytilesManaged_" + shorthand;
183 std::ostringstream struct_text;
185 struct_text <<
"const struct Tileset " << tileset_name <<
" =\n";
186 struct_text <<
"{\n";
187 struct_text <<
" .isCompressed = TRUE,\n";
188 struct_text <<
" .isSecondary = " << is_secondary_value <<
",\n";
189 struct_text <<
" .tiles = " << tiles_value <<
",\n";
190 struct_text <<
" .palettes = " << palettes_value <<
",\n";
191 struct_text <<
" .metatiles = " << metatiles_value <<
",\n";
192 struct_text <<
" .metatileAttributes = " << attributes_value <<
",\n";
193 struct_text <<
" .callback = NULL,\n";
194 struct_text <<
"};\n";
197 std::ofstream out{headers_path, std::ios::app};
198 if (!out.is_open()) {
203 out << struct_text.str();
#define PT_TRY_ASSIGN_CHAIN_ERR(var, expr, return_type,...)
Unwraps a ChainableResult, chaining a new error message on failure.
High-level facade for parsing C/C++ source files.
A result type that maintains a chainable sequence of errors for debugging and error reporting.
Represents a parsed C struct variable declaration with its initializer fields.
const std::vector< DesignatedInitializerField > & fields() const
Returns all designated initializer fields.
static const Style bold
Bold text formatting.
virtual std::string format(const std::string &format_str, const std::vector< FormatParam > ¶ms) const
Formats a string with styled parameters using fmtlib syntax.