Fluid: Add automated MergeBack

This commit is contained in:
Matthias Melcher 2026-01-04 20:43:26 +01:00
parent 811a188bbf
commit 7306b66d99
7 changed files with 694 additions and 375 deletions

View File

@ -234,6 +234,7 @@ int Application::run(int argc,char **argv) {
}
#endif
start_auto_mergeback();
Fl::run();
proj.undo.clear();
@ -507,7 +508,9 @@ bool Application::open_project_file(const std::string &filename_arg) {
// clear the project and merge a file by the given name
new_project(false);
return merge_project_file(new_filename);
bool success = merge_project_file(new_filename);
if (success) mergeback_on_load();
return success;
}

View File

@ -1226,8 +1226,6 @@ DeclBlock_Node::DeclBlock_Node()
Destructor.
*/
DeclBlock_Node::~DeclBlock_Node() {
if (after)
::free((void*)after);
}
/**
@ -1253,7 +1251,7 @@ Node *DeclBlock_Node::make(Strategy strategy) {
DeclBlock_Node *o = new DeclBlock_Node();
o->name("#if 1");
o->write_map_ = CODE_IN_SOURCE;
o->after = fl_strdup("#endif");
o->end_code_ = "#endif";
o->add(anchor, strategy);
o->factory = this;
return o;
@ -1272,7 +1270,7 @@ void DeclBlock_Node::write_properties(fld::io::Project_Writer &f) {
if (write_map_ != CODE_IN_SOURCE)
f.write_string("map %d", write_map_);
f.write_string("after");
f.write_word(after);
f.write_word(end_code().c_str());
}
/**
@ -1286,7 +1284,7 @@ void DeclBlock_Node::read_property(fld::io::Project_Reader &f, const char *c) {
} else if(!strcmp(c,"map")) {
write_map_ = (int)atol(f.read_word());
} else if (!strcmp(c,"after")) {
storestring(f.read_word(),after);
end_code(f.read_word());
} else {
Node::read_property(f, c);
}
@ -1317,12 +1315,11 @@ void DeclBlock_Node::write_static(fld::io::Code_Writer& f) {
Write the \b after static code to the source file, and to the header file if declared public.
*/
void DeclBlock_Node::write_static_after(fld::io::Code_Writer& f) {
const char* c = after;
if (c && *c) {
if (!end_code().empty()) {
if (write_map_ & STATIC_IN_HEADER)
f.write_h("%s\n", c);
f.write_h("%s\n", end_code().c_str());
if (write_map_ & STATIC_IN_SOURCE)
f.write_c("%s\n", c);
f.write_c("%s\n", end_code().c_str());
}
}
@ -1344,12 +1341,11 @@ void DeclBlock_Node::write_code1(fld::io::Code_Writer& f) {
Write the \b after code to the source file, and to the header file if declared public.
*/
void DeclBlock_Node::write_code2(fld::io::Code_Writer& f) {
const char* c = after;
if (c && *c) {
if (!end_code().empty()) {
if (write_map_ & CODE_IN_HEADER)
f.write_h("%s\n", c);
f.write_h("%s\n", end_code().c_str());
if (write_map_ & CODE_IN_SOURCE)
f.write_c("%s\n", c);
f.write_c("%s\n", end_code().c_str());
}
}

View File

@ -208,8 +208,9 @@ public:
STATIC_IN_HEADER = 4,
STATIC_IN_SOURCE = 8
};
private:
const char* after { nullptr }; ///< code after all children of this block
std::string end_code_; ///< code after all children of this block
int write_map_ { CODE_IN_SOURCE }; ///< see enum above
public:
@ -229,8 +230,8 @@ public:
int is_public() const override;
Type type() const override { return Type::DeclBlock; }
bool is_a(Type inType) const override { return (inType==Type::DeclBlock) ? true : super::is_a(inType); }
const char *end_code() { return after; }
void end_code(const char *c) { storestring(c, after); }
std::string end_code() { return end_code_; }
void end_code(const std::string& p) { storestring(p, end_code_); }
int write_map() { return write_map_; }
void write_map(int v) { write_map_ = v; }
};
@ -242,6 +243,7 @@ class Comment_Node : public Node
public:
typedef Node super;
static Comment_Node prototype;
private:
char in_c_, in_h_, style_;
@ -270,17 +272,18 @@ class Class_Node : public Node
public:
typedef Node super;
static Class_Node prototype;
private:
std::string base_class_;
std::string prefix_;
char public_;
public:
Class_Node();
~Class_Node();
// state variables for output:
char write_public_state; // true when public: has been printed
Class_Node* parent_class; // save class if nested
//
Node *make(Strategy strategy) override;
void write_code1(fld::io::Code_Writer& f) override;
void write_code2(fld::io::Code_Writer& f) override;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -617,14 +617,24 @@ int Mergeback::merge_back(const std::string &s, const std::string &p, Task task)
0 if MergeBack is not enabled,
or the result of the merge_back function.
*/
int mergeback_code_files(Project &proj)
int mergeback_code_files(Project &proj, Mergeback::Feedback feedback)
{
static bool recursion_lock = false;
if (recursion_lock) return;
recursion_lock = true;
Fluid.flush_text_widgets();
if (!proj.proj_filename) return 1;
if (!proj.proj_filename) {
recursion_lock = false;
return 1;
}
if (!proj.write_mergeback_data) {
fl_message("MergeBack is not enabled for this project.\n"
"Please enable MergeBack in the project settings\n"
"dialog and re-save the project file and the code.");
if (feedback & Mergeback::CHATTY) {
fl_message("MergeBack is not enabled for this project.\n"
"Please enable MergeBack in the project settings\n"
"dialog and re-save the project file and the code.");
}
recursion_lock = false;
return 0;
}
@ -633,7 +643,7 @@ int mergeback_code_files(Project &proj)
#if 1
if (!Fluid.batch_mode) {
// Depending on the workflow in interactive mode, an external copy of
// Fluid may have written the source code elswhere (e.g. in a CMake setup).
// Fluid may have written the source code elsewhere (e.g. in a CMake setup).
// Fluid tries to keep track of the last write location of a source file
// matching a project, and uses that location instead.
// TODO: this is not working as expected yet.
@ -656,15 +666,32 @@ int mergeback_code_files(Project &proj)
}
if (!Fluid.batch_mode) proj.leave_project_dir();
if (c==0) fl_message("Comparing\n \"%s\"\nto\n \"%s\"\n\n"
"MergeBack found no external modifications\n"
"in the source code.",
code_filename.c_str(), proj_filename.c_str());
if (c==-2) fl_message("No corresponding source code file found.");
if (feedback & Mergeback::CHATTY) {
if (c==0) fl_message("Comparing\n \"%s\"\nto\n \"%s\"\n\n"
"MergeBack found no external modifications\n"
"in the source code.",
code_filename.c_str(), proj_filename.c_str());
if (c==-2) fl_message("No corresponding source code file found.");
}
recursion_lock = false;
return c;
}
void mergeback_cb(Fl_Widget *, void *) {
mergeback_code_files(Fluid.proj);
mergeback_code_files(Fluid.proj, Mergeback::CHATTY);
}
void mergeback_on_load() {
mergeback_code_files(Fluid.proj, Mergeback::QUIET);
}
static int app_event_handler(int event) {
if (event == FL_APP_ACTIVATE) {
mergeback_code_files(Fluid.proj, Mergeback::QUIET);
}
return 0;
}
void start_auto_mergeback() {
Fl::add_handler(app_event_handler);
}

View File

@ -35,13 +35,14 @@ namespace proj {
*/
class Mergeback
{
public:
public:
enum class Tag {
GENERIC = 0, CODE, MENU_CALLBACK, WIDGET_CALLBACK, UNUSED_
};
enum class Task {
ANALYSE = 0, INTERACTIVE, APPLY, APPLY_IF_SAFE = 3
};
enum Feedback { QUIET = 0, CHATTY = 1 };
protected:
/// Apply mergeback for this project.
Project &proj_;
@ -88,5 +89,8 @@ extern int merge_back(const std::string &s, const std::string &p, int task);
} // namespace proj
} // namespace fld
extern void start_auto_mergeback();
extern void mergeback_on_load();
#endif // FLUID_PROJ_MERGEBACK_H