From 1d0619b445bc4c147645bf5d9194ff9b04f0ddd9 Mon Sep 17 00:00:00 2001 From: Matthias Melcher Date: Sat, 1 Aug 2026 16:41:45 +0200 Subject: [PATCH] Fluid: extend mergeback to custom code (#1322) --- fluid/nodes/Widget_Node.cxx | 4 +++ fluid/proj/mergeback.cxx | 65 ++++++++++++++++++++++++++++++++++--- fluid/proj/mergeback.h | 12 ++++++- 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/fluid/nodes/Widget_Node.cxx b/fluid/nodes/Widget_Node.cxx index b0f88ad56..f9690c8f7 100644 --- a/fluid/nodes/Widget_Node.cxx +++ b/fluid/nodes/Widget_Node.cxx @@ -832,7 +832,9 @@ void Widget_Node::write_code1(fluid::io::Code_Writer& f) { write_widget_code(f); if (!extra_code(2).empty()) { + f.tag(Mergeback::Tag::GENERIC, Mergeback::Tag::SETUP, 0); f.write_c_indented(extra_code(2), 0, '\n'); + f.tag(Mergeback::Tag::SETUP, Mergeback::Tag::GENERIC, get_uid()); } } @@ -1066,7 +1068,9 @@ void Widget_Node::write_block_close(fluid::io::Code_Writer& f) { void Widget_Node::write_code2(fluid::io::Code_Writer& f) { if (!extra_code(3).empty()) { + f.tag(Mergeback::Tag::GENERIC, Mergeback::Tag::FINALIZE, 0); f.write_c_indented(extra_code(3), 0, '\n'); + f.tag(Mergeback::Tag::FINALIZE, Mergeback::Tag::GENERIC, get_uid()); } write_block_close(f); } diff --git a/fluid/proj/mergeback.cxx b/fluid/proj/mergeback.cxx index 88450053f..690e377a0 100644 --- a/fluid/proj/mergeback.cxx +++ b/fluid/proj/mergeback.cxx @@ -281,6 +281,29 @@ void Mergeback::analyse_code(unsigned long code_crc, unsigned long tag_crc, int } } +/** Analyse the block and its corresponding Code Type. + Return findings in num_changed_code, num_changed_code, and num_uid_not_found. + */ +void Mergeback::analyse_extra_code(int index, unsigned long code_crc, unsigned long tag_crc, int uid) { + Node *tp = proj_.tree.find_by_uid(uid); + Widget_Node *wp = dynamic_cast(tp); + if (wp) { + std::string code = wp->extra_code(index); code += "\n"; + unsigned long project_crc = fluid::CRC32::block(code); + // check if the code and project crc are the same, so this modification was already applied + if (project_crc!=code_crc) { + num_changed_code++; + // check if the block change on the project side as well, so we may override changes + if (project_crc!=tag_crc) { + num_possible_override++; + } + } + } else { + num_changed_code++; + num_uid_not_found++; + } +} + /** Decode a 22 bytes string of three distinct characters into a 32 bit integer. \param[in] text at least 22 characters '-', '~', and '=' @@ -372,7 +395,16 @@ void Mergeback::print_tag(FILE *out, Tag prev_type, Tag next_type, uint16_t uid, \return The formatted tag string. */ std::string Mergeback::format_tag(Tag prev_type, Tag next_type, uint16_t uid, uint32_t crc) { - static const char *tag_lut[] = { "----------", "-- code --", " callback ", " callback " }; + static const char *tag_lut[] = { + "----------", + "-- code --", + " callback ", + " callback ", + "- code 0 -", + "- code 1 -", + "- setup --", + " finalize " + }; static const char *lut[] = { "--", "-~", "~-", "~~", "-=", "=-", "~=", "=~" }; std::string result; result += "//fl "; // Distinct start of tag using utf8 @@ -390,14 +422,14 @@ std::string Mergeback::format_tag(Tag prev_type, Tag next_type, uint16_t uid, ui // Write a string indicating the type of editable text #if 0 if ( next_type != Tag::GENERIC) { - result += tag_lut[(nt%4)]; + result += tag_lut[(nt%((int)Tag::END_OF_LIST_))]; } else if (prev_type != Tag::GENERIC) { - result += tag_lut[(pt%4)]; + result += tag_lut[(pt%((int)Tag::END_OF_LIST_))]; } else { result += tag_lut[0]; } #else - result += tag_lut[(nt%4)]; + result += tag_lut[(nt%((int)Tag::END_OF_LIST_))]; #endif // Write the second 32 bit word as an encoded divider line for (int i=30; i>=0; i-=3) result += lut[(crc>>i)&7]; @@ -473,6 +505,12 @@ int Mergeback::analyse() { case Tag::CODE: analyse_code(crc.value(), tag_crc, uid); break; + case Tag::CODE0: + case Tag::CODE1: + case Tag::SETUP: + case Tag::FINALIZE: + analyse_extra_code(((int)tag_type)-((int)Tag::CODE0), crc.value(), tag_crc, uid); + break; default: break; } } @@ -515,6 +553,23 @@ int Mergeback::apply_code(long block_end, long block_start, unsigned long code_c return 0; } +/** Apply callback mergebacks from the code file to the project. + \return 1 if the project changed + */ +int Mergeback::apply_extra_code(int index, long block_end, long block_start, unsigned long code_crc, int uid) { + Node *tp = proj_.tree.find_by_uid(uid); + Widget_Node *wp = dynamic_cast(tp); + if (wp) { + std::string cb = wp->extra_code(index); cb += "\n"; + uint32_t project_crc = fluid::CRC32::block(cb); + if (project_crc!=code_crc) { + wp->extra_code(index, read_and_unindent_block(block_start, block_end).c_str()); + return 1; + } + } + return 0; +} + /** Apply all possible mergebacks from the code file to the project. The code file must be open for reading already. \return -1 if reading a tag failed, 0 if nothing changed, 1 if the project changed @@ -557,6 +612,8 @@ int Mergeback::apply() { changed |= apply_callback(block_end, block_start, crc.value(), uid); } else if (tag_type==Tag::CODE) { changed |= apply_code(block_end, block_start, crc.value(), uid); + } else if (tag_type==Tag::CODE0 || tag_type==Tag::CODE1 || tag_type==Tag::SETUP || tag_type==Tag::FINALIZE) { + changed |= apply_extra_code(((int)tag_type)-((int)Tag::CODE0), block_end, block_start, crc.value(), uid); } } // reset everything for the next block diff --git a/fluid/proj/mergeback.h b/fluid/proj/mergeback.h index 369d4dd70..24c1003ed 100644 --- a/fluid/proj/mergeback.h +++ b/fluid/proj/mergeback.h @@ -37,7 +37,15 @@ class Mergeback { public: enum class Tag { - GENERIC = 0, CODE, MENU_CALLBACK, WIDGET_CALLBACK, UNUSED_ + GENERIC = 0, // Code that is auto generated and can not be edited + CODE, // Code blocks in the Function_Node + MENU_CALLBACK, // Code that is generated for a menu callback function + WIDGET_CALLBACK, // Code for all other widget callbacks + CODE0, CODE1, // Not used + SETUP, // Code that is added at instantiation before children + FINALIZE, // Code that is added at instantiation after children + UNUSED_, // Mark a tag that is not used + END_OF_LIST_ = UNUSED_ }; enum class Task { ANALYSE = 0, INTERACTIVE, APPLY, APPLY_IF_SAFE @@ -65,8 +73,10 @@ protected: std::string read_and_unindent_block(long start, long end); void analyse_callback(unsigned long code_crc, unsigned long tag_crc, int uid); void analyse_code(unsigned long code_crc, unsigned long tag_crc, int uid); + void analyse_extra_code(int index, unsigned long code_crc, unsigned long tag_crc, int uid); int apply_callback(long block_end, long block_start, unsigned long code_crc, int uid); int apply_code(long block_end, long block_start, unsigned long code_crc, int uid); + int apply_extra_code(int index, long block_end, long block_start, unsigned long code_crc, int uid); static uint32_t decode_trichar32(const char *text); static void print_trichar32(FILE *out, uint32_t value);