mirror of
https://github.com/fltk/fltk.git
synced 2026-09-25 09:53:46 +08:00
Fluid: clean up Code_Writer
Build and Test / build-linux (push) Has been cancelled
Build and Test / build-wayland (push) Has been cancelled
Build and Test / build-wayland-arm64 (push) Has been cancelled
Build and Test / build-macos (push) Has been cancelled
Build and Test / build-windows (push) Has been cancelled
Build and Test / build-windows-arm (push) Has been cancelled
Build and Test / build-linux (push) Has been cancelled
Build and Test / build-wayland (push) Has been cancelled
Build and Test / build-wayland-arm64 (push) Has been cancelled
Build and Test / build-macos (push) Has been cancelled
Build and Test / build-windows (push) Has been cancelled
Build and Test / build-windows-arm (push) Has been cancelled
This commit is contained in:
+184
-117
@@ -281,9 +281,9 @@ void Code_Writer::write_cstring(fluid::string_view text) {
|
||||
// A line break would be ok here. Do not put linebreak in front of
|
||||
// following characters (0b10......)
|
||||
if (linelength >= 78) { crc_puts(next_line); linelength = 0; }
|
||||
linelength++;
|
||||
}
|
||||
crc_putc(c);
|
||||
linelength++;
|
||||
break;
|
||||
}
|
||||
// otherwise we must print it as an octal constant:
|
||||
@@ -453,7 +453,7 @@ void Code_Writer::write_c_indented(const std::string& codeblock, int additional_
|
||||
}
|
||||
|
||||
/**
|
||||
Return true if the type can be the member of a class.
|
||||
Return true if the type can be a member of a class.
|
||||
|
||||
Some types are treated differently if they are inside class. Especially within
|
||||
a Widget Class, children that are widgets are written as part of the
|
||||
@@ -481,7 +481,7 @@ bool is_class_member(Node *t) {
|
||||
\return false if it is followed by a widget or code
|
||||
\see is_class_member(Node *t)
|
||||
*/
|
||||
bool is_comment_before_class_member(Node *q) {
|
||||
static bool is_comment_before_class_member(Node *q) {
|
||||
if (dynamic_cast<Comment_Node*>(q) && q->next && q->next->level==q->level) {
|
||||
if (dynamic_cast<Comment_Node*>(q->next))
|
||||
return is_comment_before_class_member(q->next);
|
||||
@@ -497,11 +497,9 @@ bool is_comment_before_class_member(Node *q) {
|
||||
\return pointer to the next sibling
|
||||
*/
|
||||
Node* Code_Writer::write_static(Node* p) {
|
||||
if (write_codeview) p->header_static.start = header_pos();
|
||||
if (write_codeview) p->code_static.start = code_pos();
|
||||
mark_start(p->static_data);
|
||||
p->write_static(*this);
|
||||
if (write_codeview) p->code_static.end = code_pos();
|
||||
if (write_codeview) p->header_static.end = header_pos();
|
||||
mark_end(p->static_data);
|
||||
|
||||
Node* q;
|
||||
for (q = p->next; q && q->level > p->level;) {
|
||||
@@ -522,11 +520,9 @@ Node* Code_Writer::write_code(Node* p) {
|
||||
// write all code that comes before the children code
|
||||
// (but don't write the last comment until the very end)
|
||||
if (!(p==Fluid.proj.tree.last && dynamic_cast<Comment_Node*>(p))) {
|
||||
if (write_codeview) p->code1.start = code_pos();
|
||||
if (write_codeview) p->header1.start = header_pos();
|
||||
mark_start(p->setup_node);
|
||||
p->write_code1(*this);
|
||||
if (write_codeview) p->code1.end = code_pos();
|
||||
if (write_codeview) p->header1.end = header_pos();
|
||||
mark_end(p->setup_node);
|
||||
}
|
||||
// recursively write the code of all children
|
||||
Node* q;
|
||||
@@ -545,11 +541,9 @@ Node* Code_Writer::write_code(Node* p) {
|
||||
}
|
||||
|
||||
// write all code that come after the children
|
||||
if (write_codeview) p->code2.start = code_pos();
|
||||
if (write_codeview) p->header2.start = header_pos();
|
||||
mark_start(p->finalize_node);
|
||||
p->write_code2(*this);
|
||||
if (write_codeview) p->code2.end = code_pos();
|
||||
if (write_codeview) p->header2.end = header_pos();
|
||||
mark_end(p->finalize_node);
|
||||
|
||||
for (q = p->next; q && q->level > p->level;) {
|
||||
if (is_class_member(q) || is_comment_before_class_member(q)) {
|
||||
@@ -567,17 +561,15 @@ Node* Code_Writer::write_code(Node* p) {
|
||||
} else {
|
||||
for (q = p->next; q && q->level > p->level;) q = write_code(q);
|
||||
// write all code that come after the children
|
||||
if (write_codeview) p->code2.start = code_pos();
|
||||
if (write_codeview) p->header2.start = header_pos();
|
||||
mark_start(p->finalize_node);
|
||||
p->write_code2(*this);
|
||||
if (write_codeview) p->code2.end = code_pos();
|
||||
if (write_codeview) p->header2.end = header_pos();
|
||||
mark_end(p->finalize_node);
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
/**
|
||||
Write the source and header files for the current design.
|
||||
Write source code and header files.
|
||||
|
||||
If the files already exist, they will be overwritten only if the content
|
||||
has changed. This conservative approach helps reduce unnecessary recompilation.
|
||||
@@ -589,109 +581,92 @@ Node* Code_Writer::write_code(Node* p) {
|
||||
\return 0 if the operation failed, 1 if it was successful
|
||||
*/
|
||||
int Code_Writer::write_code(const std::string& code_arg, const std::string& header_arg, bool to_codeview) {
|
||||
code_filename = code_arg;
|
||||
header_filename = header_arg;
|
||||
write_codeview = to_codeview;
|
||||
unique_id_list.clear();
|
||||
indentation = 0;
|
||||
current_class = nullptr;
|
||||
current_widget_class = nullptr;
|
||||
|
||||
// Always use string stream buffers for output
|
||||
code_buffer.str("");
|
||||
code_buffer.clear();
|
||||
header_buffer.str("");
|
||||
header_buffer.clear();
|
||||
|
||||
// Remember the last code file location for MergeBack
|
||||
if (!code_arg.empty() && proj_.write_mergeback_data && !to_codeview) {
|
||||
std::string filename = proj_.projectfile_path() + proj_.projectfile_name();
|
||||
int i, n = (int)filename.size();
|
||||
for (i=0; i<n; i++) if (filename[i]=='\\') filename[i] = '/';
|
||||
Fl_Preferences build_records(Fl_Preferences::USER_L, "fltk.org", "fluid-build");
|
||||
Fl_Preferences path(build_records, filename.c_str());
|
||||
path.set("code", code_arg);
|
||||
if (!code_arg.empty() && proj_.write_mergeback_data && !to_codeview)
|
||||
remember_mergeback_paths();
|
||||
|
||||
// Write the prologue comment, which may be a copyright notice or other
|
||||
Node* first_node = write_prologue_comment();
|
||||
write_prologue();
|
||||
write_i18n_prologue();
|
||||
|
||||
for (Node* p = first_node; p;) {
|
||||
// write all static data for this & all children first
|
||||
write_static(p);
|
||||
// then write the nested code:
|
||||
p = write_code(p);
|
||||
}
|
||||
|
||||
write_epilogue();
|
||||
write_epilogue_comment();
|
||||
|
||||
// For codeview mode, strings are available via code_string() / header_string()
|
||||
if (write_codeview)
|
||||
return 1;
|
||||
else
|
||||
return flush();
|
||||
}
|
||||
|
||||
/**
|
||||
If the first node in the project is a comment, emit it before the actual prologue.
|
||||
\return the node after the comment (or the first node if it was not a comment)
|
||||
*/
|
||||
Node* Code_Writer::write_prologue_comment() {
|
||||
// if the first entry in the Type tree is a comment, then it is probably
|
||||
// a copyright notice. We print that before anything else in the file!
|
||||
Node* first_node = Fluid.proj.tree.first;
|
||||
if (first_node && dynamic_cast<Comment_Node*>(first_node)) {
|
||||
if (write_codeview) {
|
||||
first_node->code1.start = first_node->code2.start = code_pos();
|
||||
first_node->header1.start = first_node->header2.start = header_pos();
|
||||
}
|
||||
mark_start(first_node->setup_node);
|
||||
mark_start(first_node->finalize_node);
|
||||
// it is ok to write non-recursive code here, because comments have no children or code2 blocks
|
||||
first_node->write_code1(*this);
|
||||
if (write_codeview) {
|
||||
first_node->code1.end = first_node->code2.end = code_pos();
|
||||
first_node->header1.end = first_node->header2.end = header_pos();
|
||||
}
|
||||
mark_end(first_node->setup_node);
|
||||
mark_end(first_node->finalize_node);
|
||||
first_node = first_node->next;
|
||||
}
|
||||
return first_node;
|
||||
}
|
||||
|
||||
/**
|
||||
Write the prologue of the source and header files, including the include guard
|
||||
and any necessary includes.
|
||||
*/
|
||||
void Code_Writer::write_prologue()
|
||||
{
|
||||
char version[128];
|
||||
fl_snprintf(version, sizeof(version),
|
||||
"// generated by Fast Light User Interface Designer (fluid) version %.4f\n\n",
|
||||
FL_VERSION);
|
||||
write_h(std::string(version));
|
||||
crc_puts(version);
|
||||
{
|
||||
// Creating the include guard is more involved than it seems at first glance.
|
||||
// The include guard is deduced from header filename. However, if the
|
||||
// filename contains unicode characters, they need to be encoded using
|
||||
// \Uxxxxxxxx or \\uxxxx encoding to form a valid macro identifier.
|
||||
//
|
||||
// But that approach is not portable. Windows does not normalize Unicode
|
||||
// (ö is the letter \u00F6). macOS normalizes to NFD (ö is \u006F\u0308,
|
||||
// o followed by a Combining Diaresis ¨).
|
||||
//
|
||||
// To make the include guard consistent across l=platforms, it can be
|
||||
// explicitly set by the user in the Project Settings.
|
||||
std::string macro_name_str = proj_.include_guard;
|
||||
if (macro_name_str.empty()) {
|
||||
std::ostringstream macro_name;
|
||||
std::string header_name;
|
||||
const char* a = nullptr;
|
||||
if (write_codeview) {
|
||||
header_name = proj_.headerfile_name();
|
||||
a = header_name.c_str();
|
||||
} else {
|
||||
a = fl_filename_name(header_arg.c_str());
|
||||
}
|
||||
const char* b = a + strlen(a);
|
||||
int len = 0;
|
||||
unsigned ucs = fl_utf8decode(a, b, &len);
|
||||
if ((ucs > 127) || (!isalpha(ucs) && (ucs != '_')))
|
||||
macro_name << '_';
|
||||
while (a < b) {
|
||||
ucs = fl_utf8decode(a, b, &len);
|
||||
if (ucs > 0x0000ffff) { // large unicode character
|
||||
macro_name << "\\U" << std::setw(8) << std::setfill('0') << std::hex << ucs;
|
||||
} else if (ucs > 127) { // small unicode character or not an ASCI letter or digit
|
||||
macro_name << "\\u" << std::setw(4) << std::setfill('0') << std::hex << ucs;
|
||||
} else if (!isalnum(ucs)) {
|
||||
macro_name << '_';
|
||||
} else {
|
||||
macro_name << (char)ucs;
|
||||
}
|
||||
a += len;
|
||||
}
|
||||
macro_name_str = macro_name.str();
|
||||
}
|
||||
write_h("#ifndef " + macro_name_str + "\n");
|
||||
write_h("#define " + macro_name_str + "\n");
|
||||
}
|
||||
|
||||
std::string guard = header_guard_macro();
|
||||
write_h("#ifndef " + guard + "\n");
|
||||
write_h("#define " + guard + "\n");
|
||||
|
||||
if (proj_.avoid_early_includes==0) {
|
||||
write_h_once("#include <FL/Fl.H>");
|
||||
}
|
||||
if (!header_arg.empty() && proj_.include_H_from_C) {
|
||||
if (to_codeview) {
|
||||
if (!header_filename.empty() && proj_.include_H_from_C) {
|
||||
if (write_codeview) {
|
||||
write_c("#include \"CodeView.h\"\n");
|
||||
} else if (proj_.header_file_name[0] == '.' && strchr(proj_.header_file_name.c_str(), '/') == nullptr) {
|
||||
write_c("#include \"" + fl_filename_name_str(header_arg) + "\"\n");
|
||||
write_c("#include \"" + fl_filename_name_str(header_filename) + "\"\n");
|
||||
} else {
|
||||
write_c("#include \"" + proj_.header_file_name + "\"\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Write the internationalization prologue, including any necessary includes and macros.
|
||||
*/
|
||||
void Code_Writer::write_i18n_prologue()
|
||||
{
|
||||
std::string loc_include, loc_conditional;
|
||||
if (proj_.i18n.type==fluid::I18n_Type::GNU) {
|
||||
loc_include = proj_.i18n.gnu_include;
|
||||
@@ -743,44 +718,53 @@ int Code_Writer::write_code(const std::string& code_arg, const std::string& head
|
||||
write_c("#endif\n");
|
||||
}
|
||||
}
|
||||
for (Node* p = first_node; p;) {
|
||||
// write all static data for this & all children first
|
||||
write_static(p);
|
||||
// then write the nested code:
|
||||
p = write_code(p);
|
||||
}
|
||||
}
|
||||
|
||||
write_h("#endif\n");
|
||||
/**
|
||||
Write the epilogue of the source and header files, including the include guard.
|
||||
*/
|
||||
void Code_Writer::write_epilogue()
|
||||
{
|
||||
std::string guard = header_guard_macro();
|
||||
write_h("#endif // " + guard + "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
If the last node in the project is a comment, emit it after the actual epilogue.
|
||||
*/
|
||||
void Code_Writer::write_epilogue_comment() {
|
||||
Node* last_node = Fluid.proj.tree.last;
|
||||
if (last_node && (last_node != Fluid.proj.tree.first) && dynamic_cast<Comment_Node*>(last_node)) {
|
||||
if (write_codeview) {
|
||||
last_node->code1.start = last_node->code2.start = code_pos();
|
||||
last_node->header1.start = last_node->header2.start = header_pos();
|
||||
}
|
||||
mark_start(last_node->setup_node);
|
||||
mark_start(last_node->finalize_node);
|
||||
last_node->write_code1(*this);
|
||||
if (write_codeview) {
|
||||
last_node->code1.end = last_node->code2.end = code_pos();
|
||||
last_node->header1.end = last_node->header2.end = header_pos();
|
||||
}
|
||||
mark_end(last_node->setup_node);
|
||||
mark_end(last_node->finalize_node);
|
||||
}
|
||||
}
|
||||
|
||||
// For codeview mode, strings are available via code_string() / header_string()
|
||||
if (write_codeview)
|
||||
return 1;
|
||||
/**
|
||||
Write the contents of code_buffer and header_buffer..
|
||||
|
||||
If the files already exist, they will be overwritten only if the content
|
||||
has changed. This conservative approach helps reduce unnecessary recompilation.
|
||||
|
||||
\return 0 if the operation failed, 1 if it was successful
|
||||
*/
|
||||
int Code_Writer::flush()
|
||||
{
|
||||
// Write code output: to file if filename provided, to stdout otherwise
|
||||
bool code_ok = true;
|
||||
if (!code_arg.empty()) {
|
||||
code_ok = write_file_if_changed(code_arg, code_buffer.str());
|
||||
if (!code_filename.empty()) {
|
||||
code_ok = write_file_if_changed(code_filename, code_buffer.str());
|
||||
} else {
|
||||
fputs(code_buffer.str().c_str(), stdout);
|
||||
}
|
||||
|
||||
// Write header output: to file if filename provided, to stdout otherwise
|
||||
bool header_ok = true;
|
||||
if (!header_arg.empty()) {
|
||||
header_ok = write_file_if_changed(header_arg, header_buffer.str());
|
||||
if (!header_filename.empty()) {
|
||||
header_ok = write_file_if_changed(header_filename, header_buffer.str());
|
||||
} else {
|
||||
fputs(header_buffer.str().c_str(), stdout);
|
||||
}
|
||||
@@ -788,7 +772,6 @@ int Code_Writer::write_code(const std::string& code_arg, const std::string& head
|
||||
return code_ok && header_ok ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Write the public/private/protected keywords inside the class.
|
||||
This avoids repeating these words if the mode is already set.
|
||||
@@ -974,6 +957,90 @@ void fluid::CRC32::update(fluid::string_view block) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Return the macro name to use for the include guard in the header file.
|
||||
|
||||
Creating the include guard is more involved than it seems at first glance.
|
||||
The include guard is deduced from header filename. However, if the
|
||||
filename contains unicode characters, they need to be encoded using
|
||||
\Uxxxxxxxx or \\uxxxx encoding to form a valid macro identifier.
|
||||
|
||||
But that approach is not portable. Windows does not normalize Unicode
|
||||
(ö is the letter \u00F6). macOS normalizes to NFD (ö is \u006F\u0308,
|
||||
o followed by a Combining Diaresis ¨).
|
||||
|
||||
To make the include guard consistent across l=platforms, it can be
|
||||
explicitly set by the user in the Project Settings.
|
||||
*/
|
||||
std::string Code_Writer::header_guard_macro()
|
||||
{
|
||||
if (!header_guard_macro_.empty()) {
|
||||
return header_guard_macro_;
|
||||
}
|
||||
header_guard_macro_ = proj_.include_guard;
|
||||
if (header_guard_macro_.empty()) {
|
||||
std::ostringstream macro_name;
|
||||
std::string header_name;
|
||||
const char* a = nullptr;
|
||||
if (write_codeview) {
|
||||
header_name = proj_.headerfile_name();
|
||||
a = header_name.c_str();
|
||||
} else {
|
||||
a = fl_filename_name(header_filename.c_str());
|
||||
}
|
||||
const char* b = a + strlen(a);
|
||||
int len = 0;
|
||||
unsigned ucs = fl_utf8decode(a, b, &len);
|
||||
if ((ucs > 127) || (!isalpha(ucs) && (ucs != '_')))
|
||||
macro_name << '_';
|
||||
while (a < b) {
|
||||
ucs = fl_utf8decode(a, b, &len);
|
||||
if (ucs > 0x0000ffff) { // large unicode character
|
||||
macro_name << "\\U" << std::setw(8) << std::setfill('0') << std::hex << ucs;
|
||||
} else if (ucs > 127) { // small unicode character or not an ASCI letter or digit
|
||||
macro_name << "\\u" << std::setw(4) << std::setfill('0') << std::hex << ucs;
|
||||
} else if (!isalnum(ucs)) {
|
||||
macro_name << '_';
|
||||
} else {
|
||||
macro_name << (char)ucs;
|
||||
}
|
||||
a += len;
|
||||
}
|
||||
header_guard_macro_ = macro_name.str();
|
||||
}
|
||||
return header_guard_macro_;
|
||||
}
|
||||
|
||||
/**
|
||||
Remember the last code file location for MergeBack.
|
||||
This is stored in the user preferences, so that the next time the project is
|
||||
opened, the code file can be found and merged back into the project.
|
||||
*/
|
||||
void Code_Writer::remember_mergeback_paths()
|
||||
{
|
||||
std::string filename = proj_.projectfile_path() + proj_.projectfile_name();
|
||||
int i, n = (int)filename.size();
|
||||
for (i=0; i<n; i++) if (filename[i]=='\\') filename[i] = '/';
|
||||
Fl_Preferences build_records(Fl_Preferences::USER_L, "fltk.org", "fluid-build");
|
||||
Fl_Preferences path(build_records, filename.c_str());
|
||||
path.set("code", code_filename);
|
||||
}
|
||||
|
||||
void Code_Writer::mark_start(TextSpan2& span) {
|
||||
if (write_codeview) {
|
||||
span.c.start = code_pos();
|
||||
span.h.start = header_pos();
|
||||
}
|
||||
}
|
||||
|
||||
void Code_Writer::mark_end(TextSpan2& span) {
|
||||
if (write_codeview) {
|
||||
span.c.end = code_pos();
|
||||
span.h.end = header_pos();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Calculate the CRC32 of a block of text.
|
||||
This is a convenience function that creates a CRC32 object, adds the block of
|
||||
|
||||
+30
-10
@@ -36,6 +36,8 @@ struct Fd_Pointer_Tree;
|
||||
|
||||
int is_id(char c);
|
||||
|
||||
struct TextSpan2;
|
||||
|
||||
namespace fluid {
|
||||
|
||||
class Project;
|
||||
@@ -64,11 +66,11 @@ struct string_view {
|
||||
};
|
||||
|
||||
class CRC32 {
|
||||
uint32_t crc_;
|
||||
bool multi_space_ = false;
|
||||
bool line_start_ = true;
|
||||
uint32_t crc_ { 0 };
|
||||
bool multi_space_ { false };
|
||||
bool line_start_ { true };
|
||||
public:
|
||||
CRC32() : crc_(0) {}
|
||||
CRC32() = default;
|
||||
void update(fluid::string_view block);
|
||||
uint32_t value() const { return crc_; }
|
||||
void reset() { crc_ = 0; multi_space_ = false; line_start_ = true; }
|
||||
@@ -87,9 +89,13 @@ private:
|
||||
Project &proj_;
|
||||
|
||||
/// string stream buffer for generating C++ code file content
|
||||
std::ostringstream code_buffer;
|
||||
std::ostringstream code_buffer { };
|
||||
/// string stream buffer for generating C++ header file content
|
||||
std::ostringstream header_buffer;
|
||||
std::ostringstream header_buffer { };
|
||||
|
||||
std::string header_filename { };
|
||||
std::string code_filename { };
|
||||
std::string header_guard_macro_ { };
|
||||
|
||||
/// tree of unique but human-readable identifiers
|
||||
std::map<std::string, void*> unique_id_list { };
|
||||
@@ -104,10 +110,11 @@ private:
|
||||
fluid::CRC32 crc_ { };
|
||||
|
||||
/// current level of source code indentation
|
||||
int indentation = 0;
|
||||
int indentation { 0 };
|
||||
|
||||
bool file_content_matches(const std::string& filename, const std::string& content);
|
||||
bool write_file_if_changed(const std::string& filename, const std::string& content);
|
||||
int flush();
|
||||
|
||||
/// Return the current write position in the code output stream.
|
||||
int code_pos() { return (int)code_buffer.tellp(); }
|
||||
@@ -121,13 +128,13 @@ protected:
|
||||
public:
|
||||
/// set if we write abbreviated file for the source code previewer
|
||||
/// (disables binary data blocks, for example)
|
||||
bool write_codeview = false;
|
||||
bool write_codeview { false };
|
||||
/// silly thing to prevent declaring unused variables:
|
||||
/// When this symbol is on, all attempts to write code don't write
|
||||
/// anything, but set a variable if it looks like the variable "o" is used:
|
||||
int varused_test = 0;
|
||||
int varused_test { 0 };
|
||||
/// set to 1 if varused_test found that a variable is actually used
|
||||
int varused = 0;
|
||||
int varused { 0 };
|
||||
|
||||
public:
|
||||
Code_Writer(Project &proj);
|
||||
@@ -165,13 +172,26 @@ public:
|
||||
Node* write_code(Node* p);
|
||||
|
||||
int write_code(const std::string& code_arg, const std::string& header_arg, bool to_codeview=false);
|
||||
Node* write_prologue_comment();
|
||||
void write_prologue();
|
||||
void write_i18n_prologue();
|
||||
void write_epilogue();
|
||||
void write_epilogue_comment();
|
||||
|
||||
/// Return the generated source code as a string (valid after write_code() with to_codeview=true).
|
||||
std::string code_string() const { return code_buffer.str(); }
|
||||
/// Return the generated header code as a string (valid after write_code() with to_codeview=true).
|
||||
std::string header_string() const { return header_buffer.str(); }
|
||||
|
||||
/// Return the predefined header guard, or generate one based on the header filename if not set.
|
||||
std::string header_guard_macro();
|
||||
/// Remember the last destination for later MergeBack calls.
|
||||
void remember_mergeback_paths();
|
||||
|
||||
void tag(proj::Mergeback::Tag prev_type, proj::Mergeback::Tag next_type, unsigned short uid);
|
||||
|
||||
void mark_start(TextSpan2& span);
|
||||
void mark_end(TextSpan2& span);
|
||||
};
|
||||
|
||||
} // namespace io
|
||||
|
||||
+7
-2
@@ -85,6 +85,10 @@ struct TextSpan {
|
||||
int start = -1, end = -1;
|
||||
};
|
||||
|
||||
struct TextSpan2 {
|
||||
TextSpan h, c;
|
||||
};
|
||||
|
||||
int storestring(const char *n, const char * & p, int nostrip=0);
|
||||
int storestring(const std::string& n, std::string& p, int nostrip=0);
|
||||
|
||||
@@ -180,8 +184,9 @@ public: // things that should not be public:
|
||||
std::string callback_name(fluid::io::Code_Writer& f);
|
||||
|
||||
// text positions of this type in code, header, and project file (see codeview)
|
||||
TextSpan code_static, code1, code2;
|
||||
TextSpan header1, header2, header_static;
|
||||
TextSpan2 static_data;
|
||||
TextSpan2 setup_node;
|
||||
TextSpan2 finalize_node;
|
||||
TextSpan proj1, proj2;
|
||||
|
||||
public:
|
||||
|
||||
@@ -107,14 +107,14 @@ Node *Tree::find_in_text(int text_type, int crsr) {
|
||||
for (auto node: all_nodes()) {
|
||||
switch (text_type) {
|
||||
case 0:
|
||||
if (crsr >= node->code1.start && crsr < node->code1.end) return node;
|
||||
if (crsr >= node->code2.start && crsr < node->code2.end) return node;
|
||||
if (crsr >= node->code_static.start && crsr < node->code_static.end) return node;
|
||||
if (crsr >= node->setup_node.c.start && crsr < node->setup_node.c.end) return node;
|
||||
if (crsr >= node->finalize_node.c.start && crsr < node->finalize_node.c.end) return node;
|
||||
if (crsr >= node->static_data.c.start && crsr < node->static_data.c.end) return node;
|
||||
break;
|
||||
case 1:
|
||||
if (crsr >= node->header1.start && crsr < node->header1.end) return node;
|
||||
if (crsr >= node->header2.start && crsr < node->header2.end) return node;
|
||||
if (crsr >= node->header_static.start && crsr < node->header_static.end) return node;
|
||||
if (crsr >= node->setup_node.h.start && crsr < node->setup_node.h.end) return node;
|
||||
if (crsr >= node->finalize_node.h.start && crsr < node->finalize_node.h.end) return node;
|
||||
if (crsr >= node->static_data.h.start && crsr < node->static_data.h.end) return node;
|
||||
break;
|
||||
case 2:
|
||||
if (crsr >= node->proj1.start && crsr < node->proj1.end) return node;
|
||||
|
||||
@@ -50,24 +50,24 @@ void update_codeview_position() {
|
||||
if (cv_source->visible_r()) {
|
||||
switch (cv_code_choice) {
|
||||
case 0: // prolog: not yet (include statements)
|
||||
pos0 = Fluid.proj.tree.current->code1.start;
|
||||
pos1 = Fluid.proj.tree.current->code2.end;
|
||||
pos0 = Fluid.proj.tree.current->setup_node.c.start;
|
||||
pos1 = Fluid.proj.tree.current->finalize_node.c.end;
|
||||
break;
|
||||
case 1: // static: callbacks, menu declarations
|
||||
pos0 = Fluid.proj.tree.current->code_static.start;
|
||||
pos1 = Fluid.proj.tree.current->code_static.end;
|
||||
pos0 = Fluid.proj.tree.current->static_data.c.start;
|
||||
pos1 = Fluid.proj.tree.current->static_data.c.end;
|
||||
break;
|
||||
case 2: // code: entire implementation block including children
|
||||
pos0 = Fluid.proj.tree.current->code1.start;
|
||||
pos1 = Fluid.proj.tree.current->code2.end;
|
||||
pos0 = Fluid.proj.tree.current->setup_node.c.start;
|
||||
pos1 = Fluid.proj.tree.current->finalize_node.c.end;
|
||||
break;
|
||||
case 3: // code1: all implementation code before the children
|
||||
pos0 = Fluid.proj.tree.current->code1.start;
|
||||
pos1 = Fluid.proj.tree.current->code1.end;
|
||||
pos0 = Fluid.proj.tree.current->setup_node.c.start;
|
||||
pos1 = Fluid.proj.tree.current->setup_node.c.end;
|
||||
break;
|
||||
case 4: // code1: all implementation code before the children
|
||||
pos0 = Fluid.proj.tree.current->code2.start;
|
||||
pos1 = Fluid.proj.tree.current->code2.end;
|
||||
pos0 = Fluid.proj.tree.current->finalize_node.c.start;
|
||||
pos1 = Fluid.proj.tree.current->finalize_node.c.end;
|
||||
break;
|
||||
}
|
||||
if (pos0>=0) {
|
||||
@@ -82,20 +82,20 @@ void update_codeview_position() {
|
||||
switch (cv_code_choice) {
|
||||
case 0: // prolog: not yet (include statements)
|
||||
case 1: // static: callbacks, menu declarations
|
||||
pos0 = Fluid.proj.tree.current->header_static.start;
|
||||
pos1 = Fluid.proj.tree.current->header_static.end;
|
||||
pos0 = Fluid.proj.tree.current->static_data.h.start;
|
||||
pos1 = Fluid.proj.tree.current->static_data.h.end;
|
||||
break;
|
||||
case 2: // code: entire implementation block including children
|
||||
pos0 = Fluid.proj.tree.current->header1.start;
|
||||
pos1 = Fluid.proj.tree.current->header2.end;
|
||||
pos0 = Fluid.proj.tree.current->setup_node.h.start;
|
||||
pos1 = Fluid.proj.tree.current->finalize_node.h.end;
|
||||
break;
|
||||
case 3: // code1: all implementation code before the children
|
||||
pos0 = Fluid.proj.tree.current->header1.start;
|
||||
pos1 = Fluid.proj.tree.current->header1.end;
|
||||
pos0 = Fluid.proj.tree.current->setup_node.h.start;
|
||||
pos1 = Fluid.proj.tree.current->setup_node.h.end;
|
||||
break;
|
||||
case 4: // code1: all implementation code before the children
|
||||
pos0 = Fluid.proj.tree.current->header2.start;
|
||||
pos1 = Fluid.proj.tree.current->header2.end;
|
||||
pos0 = Fluid.proj.tree.current->finalize_node.h.start;
|
||||
pos1 = Fluid.proj.tree.current->finalize_node.h.end;
|
||||
break;
|
||||
}
|
||||
if (pos0>=0) {
|
||||
@@ -375,10 +375,10 @@ static void cb_cv_code_choice_w(Fl_Choice* o, void*) {
|
||||
|
||||
Fl_Menu_Item menu_cv_code_choice_w[] = {
|
||||
{"prolog", 0, nullptr, (void*)(0), 16, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
|
||||
{"static", 0, nullptr, (void*)(1), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
|
||||
{"code", 0, nullptr, (void*)(2), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
|
||||
{"code 1", 0, nullptr, (void*)(3), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
|
||||
{"code 2", 0, nullptr, (void*)(4), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
|
||||
{"static data", 0, nullptr, (void*)(1), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
|
||||
{"instantiate", 0, nullptr, (void*)(2), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
|
||||
{"setup", 0, nullptr, (void*)(3), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
|
||||
{"finalize", 0, nullptr, (void*)(4), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
|
||||
{ nullptr, 0, nullptr, nullptr, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -517,7 +517,7 @@ Fl_Double_Window* make_codeview() {
|
||||
{ cv_autoposition = new Fl_Light_Button(172, 485, 89, 20, "Auto-Position");
|
||||
cv_autoposition->labelsize(11);
|
||||
} // Fl_Light_Button* cv_autoposition
|
||||
{ cv_code_choice_w = new Fl_Choice(265, 485, 70, 20);
|
||||
{ cv_code_choice_w = new Fl_Choice(265, 485, 90, 20);
|
||||
cv_code_choice_w->down_box(FL_BORDER_BOX);
|
||||
cv_code_choice_w->labelsize(11);
|
||||
cv_code_choice_w->textsize(11);
|
||||
|
||||
@@ -78,24 +78,24 @@ file.} open return_type void
|
||||
if (cv_source->visible_r()) {
|
||||
switch (cv_code_choice) {
|
||||
case 0: // prolog: not yet (include statements)
|
||||
pos0 = Fluid.proj.tree.current->code1.start;
|
||||
pos1 = Fluid.proj.tree.current->code2.end;
|
||||
pos0 = Fluid.proj.tree.current->setup_node.c.start;
|
||||
pos1 = Fluid.proj.tree.current->finalize_node.c.end;
|
||||
break;
|
||||
case 1: // static: callbacks, menu declarations
|
||||
pos0 = Fluid.proj.tree.current->code_static.start;
|
||||
pos1 = Fluid.proj.tree.current->code_static.end;
|
||||
pos0 = Fluid.proj.tree.current->static_data.c.start;
|
||||
pos1 = Fluid.proj.tree.current->static_data.c.end;
|
||||
break;
|
||||
case 2: // code: entire implementation block including children
|
||||
pos0 = Fluid.proj.tree.current->code1.start;
|
||||
pos1 = Fluid.proj.tree.current->code2.end;
|
||||
pos0 = Fluid.proj.tree.current->setup_node.c.start;
|
||||
pos1 = Fluid.proj.tree.current->finalize_node.c.end;
|
||||
break;
|
||||
case 3: // code1: all implementation code before the children
|
||||
pos0 = Fluid.proj.tree.current->code1.start;
|
||||
pos1 = Fluid.proj.tree.current->code1.end;
|
||||
pos0 = Fluid.proj.tree.current->setup_node.c.start;
|
||||
pos1 = Fluid.proj.tree.current->setup_node.c.end;
|
||||
break;
|
||||
case 4: // code1: all implementation code before the children
|
||||
pos0 = Fluid.proj.tree.current->code2.start;
|
||||
pos1 = Fluid.proj.tree.current->code2.end;
|
||||
pos0 = Fluid.proj.tree.current->finalize_node.c.start;
|
||||
pos1 = Fluid.proj.tree.current->finalize_node.c.end;
|
||||
break;
|
||||
}
|
||||
if (pos0>=0) {
|
||||
@@ -110,20 +110,20 @@ file.} open return_type void
|
||||
switch (cv_code_choice) {
|
||||
case 0: // prolog: not yet (include statements)
|
||||
case 1: // static: callbacks, menu declarations
|
||||
pos0 = Fluid.proj.tree.current->header_static.start;
|
||||
pos1 = Fluid.proj.tree.current->header_static.end;
|
||||
pos0 = Fluid.proj.tree.current->static_data.h.start;
|
||||
pos1 = Fluid.proj.tree.current->static_data.h.end;
|
||||
break;
|
||||
case 2: // code: entire implementation block including children
|
||||
pos0 = Fluid.proj.tree.current->header1.start;
|
||||
pos1 = Fluid.proj.tree.current->header2.end;
|
||||
pos0 = Fluid.proj.tree.current->setup_node.h.start;
|
||||
pos1 = Fluid.proj.tree.current->finalize_node.h.end;
|
||||
break;
|
||||
case 3: // code1: all implementation code before the children
|
||||
pos0 = Fluid.proj.tree.current->header1.start;
|
||||
pos1 = Fluid.proj.tree.current->header1.end;
|
||||
pos0 = Fluid.proj.tree.current->setup_node.h.start;
|
||||
pos1 = Fluid.proj.tree.current->setup_node.h.end;
|
||||
break;
|
||||
case 4: // code1: all implementation code before the children
|
||||
pos0 = Fluid.proj.tree.current->header2.start;
|
||||
pos1 = Fluid.proj.tree.current->header2.end;
|
||||
pos0 = Fluid.proj.tree.current->finalize_node.h.start;
|
||||
pos1 = Fluid.proj.tree.current->finalize_node.h.end;
|
||||
break;
|
||||
}
|
||||
if (pos0>=0) {
|
||||
@@ -224,8 +224,7 @@ if (cv_project->visible_r()) {
|
||||
}
|
||||
if (Fluid.proj.proj_filename)
|
||||
Fluid.proj.leave_project_dir();
|
||||
}} {selected
|
||||
}
|
||||
}} {}
|
||||
}
|
||||
|
||||
Function {update_codeview_timer(void*)} {
|
||||
@@ -281,8 +280,8 @@ Function {make_codeview()} {open
|
||||
} {
|
||||
Fl_Window codeview_panel {
|
||||
label {Code View}
|
||||
callback toggle_codeview_cb open
|
||||
xywh {389 507 520 515} type Double align 80 resizable size_range {384 120 0 0} visible
|
||||
callback toggle_codeview_cb open selected
|
||||
xywh {518 271 520 515} type Double align 80 resizable size_range {384 120 0 0} visible
|
||||
} {
|
||||
Fl_Tabs cv_tab {
|
||||
callback update_codeview_position_cb open
|
||||
@@ -461,7 +460,7 @@ if (e) {
|
||||
Fl_Choice cv_code_choice_w {
|
||||
callback {cv_code_choice = (int)o->mvalue()->argument();
|
||||
update_codeview_position();} open
|
||||
xywh {265 485 70 20} down_box BORDER_BOX labelsize 11 textsize 11
|
||||
xywh {265 485 90 20} down_box BORDER_BOX labelsize 11 textsize 11
|
||||
} {
|
||||
MenuItem {} {
|
||||
label prolog
|
||||
@@ -469,22 +468,22 @@ update_codeview_position();} open
|
||||
tooltip {Include statements in header or source code} xywh {0 0 100 20} labelsize 11 hide
|
||||
}
|
||||
MenuItem {} {
|
||||
label static
|
||||
label {static data}
|
||||
user_data 1 user_data_type long
|
||||
tooltip {static declarations in source code} xywh {10 10 100 20} labelsize 11
|
||||
}
|
||||
MenuItem {} {
|
||||
label code
|
||||
label instantiate
|
||||
user_data 2 user_data_type long
|
||||
tooltip {widget code block including children} xywh {20 20 100 20} labelsize 11
|
||||
}
|
||||
MenuItem {} {
|
||||
label {code 1}
|
||||
label setup
|
||||
user_data 3 user_data_type long
|
||||
tooltip {widget code block before children} xywh {30 30 100 20} labelsize 11
|
||||
}
|
||||
MenuItem {} {
|
||||
label {code 2}
|
||||
label finalize
|
||||
user_data 4 user_data_type long
|
||||
tooltip {widget code block after children} xywh {40 40 100 20} labelsize 11
|
||||
}
|
||||
|
||||
@@ -54,6 +54,6 @@ extern Fl_Choice* cv_code_choice_w;
|
||||
extern void toggle_codeview_b_cb(Fl_Button*, void*);
|
||||
Fl_Double_Window* make_codeview();
|
||||
extern Fl_Menu_Item menu_cv_code_choice_w[];
|
||||
#endif
|
||||
#endif // codeview_panel_h
|
||||
|
||||
//
|
||||
|
||||
@@ -151,4 +151,4 @@ extern Fl_Menu_Item menu_9[];
|
||||
extern Fl_Menu_Item menu_a[];
|
||||
extern Fl_Menu_Item menu_b[];
|
||||
extern Fl_Menu_Item menu_c[];
|
||||
#endif
|
||||
#endif // widget_panel_h
|
||||
|
||||
Reference in New Issue
Block a user