diff --git a/src/Makefile_Eolian.am b/src/Makefile_Eolian.am index a5635fd179..50fcc4febd 100644 --- a/src/Makefile_Eolian.am +++ b/src/Makefile_Eolian.am @@ -138,4 +138,6 @@ tests/eolian/data/override_ref.c \ tests/eolian/data/class_simple_ref_eo.h \ tests/eolian/data/class_simple_ref_legacy.h \ tests/eolian/data/import_types_ref.h \ +tests/eolian/data/docs_ref.h \ +tests/eolian/data/docs_ref_legacy.h \ $(EOLIAN_TESTS_EOS) diff --git a/src/bin/eolian/docs_generator.c b/src/bin/eolian/docs_generator.c index 5446f40049..201648891b 100644 --- a/src/bin/eolian/docs_generator.c +++ b/src/bin/eolian/docs_generator.c @@ -22,6 +22,98 @@ _indent_line(Eina_Strbuf *buf, int ind) #define DOC_LIMIT(ind) ((ind > DOC_LINE_TEST) ? (ind + DOC_LINE_OVER) \ : DOC_LINE_LIMIT) +static void +_generate_ref(const char *refn, Eina_Strbuf *wbuf) +{ + const Eolian_Declaration *decl = eolian_declaration_get_by_name(refn); + if (decl) + { + char *n = strdup(eolian_declaration_name_get(decl)); + char *p = n; + while ((p = strchr(p, '.'))) *p = '_'; + eina_strbuf_append(wbuf, n); + free(n); + return; + } + + /* not a plain declaration, so it must be struct/enum field or func */ + const char *sfx = strrchr(refn, '.'); + if (!sfx) goto noref; + + Eina_Stringshare *bname = eina_stringshare_add_length(refn, sfx - refn); + + const Eolian_Type *tp = eolian_type_struct_get_by_name(bname); + if (tp) + { + if (!eolian_type_struct_field_get(tp, sfx + 1)) goto noref; + _generate_ref(bname, wbuf); + eina_strbuf_append(wbuf, sfx); + eina_stringshare_del(bname); + return; + } + + tp = eolian_type_enum_get_by_name(bname); + if (tp) + { + const Eolian_Enum_Type_Field *efl = eolian_type_enum_field_get(tp, sfx + 1); + if (!efl) goto noref; + _generate_ref(bname, wbuf); + Eina_Stringshare *str = eolian_type_enum_field_c_name_get(efl); + eina_strbuf_append_char(wbuf, '.'); + eina_strbuf_append(wbuf, str); + eina_stringshare_del(str); + eina_stringshare_del(bname); + return; + } + + const Eolian_Class *cl = eolian_class_get_by_name(bname); + const Eolian_Function *fn = NULL; + Eolian_Function_Type ftype = EOLIAN_UNRESOLVED; + if (!cl) + { + const char *mname; + if (!strcmp(sfx, ".get")) ftype = EOLIAN_PROP_GET; + else if (!strcmp(sfx, ".set")) ftype = EOLIAN_PROP_SET; + if (ftype != EOLIAN_UNRESOLVED) + { + eina_stringshare_del(bname); + mname = sfx - 1; + while ((mname != refn) && (*mname != '.')) --mname; + if (mname == refn) goto noref; + bname = eina_stringshare_add_length(refn, mname - refn); + cl = eolian_class_get_by_name(bname); + eina_stringshare_del(bname); + } + if (cl) + { + char *meth = strndup(mname + 1, sfx - mname - 1); + fn = eolian_class_function_get_by_name(cl, meth, ftype); + if (ftype == EOLIAN_UNRESOLVED) + ftype = eolian_function_type_get(fn); + free(meth); + } + } + else + { + fn = eolian_class_function_get_by_name(cl, sfx + 1, ftype); + ftype = eolian_function_type_get(fn); + } + + if (!fn) goto noref; + + Eina_Stringshare *fcn = eolian_function_full_c_name_get(fn); + eina_strbuf_append(wbuf, fcn); + eina_stringshare_del(fcn); + if ((ftype == EOLIAN_PROP_GET) || (ftype == EOLIAN_PROPERTY)) + eina_strbuf_append(wbuf, "_get"); + else if (ftype == EOLIAN_PROP_SET) + eina_strbuf_append(wbuf, "_set"); + + return; +noref: + eina_strbuf_append(wbuf, refn); +} + int _append_section(const char *desc, int ind, int curl, Eina_Strbuf *buf, Eina_Strbuf *wbuf) @@ -40,9 +132,17 @@ _append_section(const char *desc, int ind, int curl, Eina_Strbuf *buf, } else if (*desc == '@') { - desc++; - if (isalpha(*desc)) - eina_strbuf_append(wbuf, "@ref "); + const char *ref = ++desc; + if (isalpha(*desc) || (*desc == '_')) + { + eina_strbuf_append(wbuf, "@ref "); + while (isalnum(*desc) || (*desc == '.') || (*desc == '_')) + ++desc; + if (*(desc - 1) == '.') --desc; + Eina_Stringshare *refn = eina_stringshare_add_length(ref, desc - ref); + _generate_ref(refn, wbuf); + eina_stringshare_del(refn); + } else eina_strbuf_append_char(wbuf, '@'); } diff --git a/src/tests/eolian/data/docs.eo b/src/tests/eolian/data/docs.eo index 339998c363..9da0745301 100644 --- a/src/tests/eolian/data/docs.eo +++ b/src/tests/eolian/data/docs.eo @@ -35,11 +35,18 @@ struct Opaque; [[Opaque struct docs. See @Foo for another struct.]] class Docs { [[Docs for class. - More docs for class. @.prop. + More docs for class. Testing references now. @Foo @Bar @Alias @pants + @.meth + @.prop + @.prop.get + @.prop.set + @Foo.field1 + @Bar.foo + @Docs ]] methods { meth { diff --git a/src/tests/eolian/data/docs_ref.h b/src/tests/eolian/data/docs_ref.h new file mode 100644 index 0000000000..c549bcbaea --- /dev/null +++ b/src/tests/eolian/data/docs_ref.h @@ -0,0 +1,100 @@ +#ifndef _EOLIAN_OUTPUT_H_ +#define _EOLIAN_OUTPUT_H_ + +#ifndef _DOCS_EO_CLASS_TYPE +#define _DOCS_EO_CLASS_TYPE + +typedef Eo Docs; + +#endif + +#ifndef _DOCS_EO_TYPES +#define _DOCS_EO_TYPES + +/** + * @brief This is struct Foo. It does stuff. + * + * This is a longer description for struct Foo. + * + * This is another paragraph. + * + * @since 1.66 + */ +typedef struct _Foo +{ + int field1; /** Field documentation. */ + float field2; + short field3; /** Another field documentation. */ +} Foo; + +/** Docs for enum Bar. */ +typedef enum +{ + BAR_BLAH = 0, + BAR_FOO = 1, /** Docs for foo. */ + BAR_BAR = 2 /** Docs for bar. */ +} Bar; + +/** + * @brief Docs for typedef. + * + * More docs for typedef. See @ref Bar. + * + * @since 2.0 + */ +typedef Bar Alias; + +/** Opaque struct docs. See @ref Foo for another struct. */ +typedef struct _Opaque Opaque; + + +#endif +/** + * @brief Docs for class. + * + * More docs for class. Testing references now. @ref Foo @ref Bar @ref Alias + * @ref pants @ref docs_meth @ref docs_prop_get @ref docs_prop_get + * @ref docs_prop_set @ref Foo.field1 @ref Bar.BAR_FOO @ref Docs + */ +#define DOCS_CLASS docs_class_get() + +EAPI const Eo_Class *docs_class_get(void) EINA_CONST; + +/** + * @brief Property common documentation. + * + * Set documentation. + * + * @param[in] val Value documentation. + * + * @since 1.18 + */ +EOAPI void docs_prop_set(int val); + +/** + * @brief Property common documentation. + * + * Get documentation. + * + * @return Value documentation. + * + * @since 1.18 + */ +EOAPI int docs_prop_get(void); + +/** + * @brief Method documentation. + * + * @param[out] b + * @param[out] c Another param documentation. + * + * @return Return documentation. + */ +EOAPI int docs_meth(int a, float *b, long *c); + +EOAPI extern const Eo_Event_Description _DOCS_EVENT_CLICKED; + +/** Event docs. */ +#define DOCS_EVENT_CLICKED (&(_DOCS_EVENT_CLICKED)) + +#endif diff --git a/src/tests/eolian/data/docs_ref_legacy.h b/src/tests/eolian/data/docs_ref_legacy.h new file mode 100644 index 0000000000..39c06555f2 --- /dev/null +++ b/src/tests/eolian/data/docs_ref_legacy.h @@ -0,0 +1,92 @@ +#ifndef _EOLIAN_OUTPUT_H_ +#define _EOLIAN_OUTPUT_H_ + +#ifndef _DOCS_EO_CLASS_TYPE +#define _DOCS_EO_CLASS_TYPE + +typedef Eo Docs; + +#endif + +#ifndef _DOCS_EO_TYPES +#define _DOCS_EO_TYPES + +/** + * @brief This is struct Foo. It does stuff. + * + * This is a longer description for struct Foo. + * + * This is another paragraph. + * + * @since 1.66 + */ +typedef struct _Foo +{ + int field1; /** Field documentation. */ + float field2; + short field3; /** Another field documentation. */ +} Foo; + +/** Docs for enum Bar. */ +typedef enum +{ + BAR_BLAH = 0, + BAR_FOO = 1, /** Docs for foo. */ + BAR_BAR = 2 /** Docs for bar. */ +} Bar; + +/** + * @brief Docs for typedef. + * + * More docs for typedef. See @ref Bar. + * + * @since 2.0 + */ +typedef Bar Alias; + +/** Opaque struct docs. See @ref Foo for another struct. */ +typedef struct _Opaque Opaque; + + +#endif +/** + * @brief Docs for class. + * + * More docs for class. Testing references now. @ref Foo @ref Bar @ref Alias + * @ref pants @ref docs_meth @ref docs_prop_get @ref docs_prop_get + * @ref docs_prop_set @ref Foo.field1 @ref Bar.BAR_FOO @ref Docs + */ + +/** + * @brief Property common documentation. + * + * Set documentation. + * + * @param[in] val Value documentation. + * + * @since 1.18 + */ +EAPI void docs_prop_set(Docs *obj, int val); + +/** + * @brief Property common documentation. + * + * Get documentation. + * + * @return Value documentation. + * + * @since 1.18 + */ +EAPI int docs_prop_get(const Docs *obj); + +/** + * @brief Method documentation. + * + * @param[out] b + * @param[out] c Another param documentation. + * + * @return Return documentation. + */ +EAPI int docs_meth(Docs *obj, int a, float *b, long *c); + +#endif diff --git a/src/tests/eolian/eolian_generation.c b/src/tests/eolian/eolian_generation.c index 7c35565e8b..1e745e9f6d 100644 --- a/src/tests/eolian/eolian_generation.c +++ b/src/tests/eolian/eolian_generation.c @@ -192,6 +192,25 @@ START_TEST(eolian_import) } END_TEST +START_TEST(eolian_docs) +{ + char output_filepath[PATH_MAX] = ""; + snprintf(output_filepath, PATH_MAX, "%s/eolian_output.h", +#ifdef HAVE_EVIL + (char *)evil_tmpdir_get() +#else + "/tmp" +#endif + ); + remove(output_filepath); + fail_if(0 != _eolian_gen_execute(PACKAGE_DATA_DIR"/data/docs.eo", "--eo --gh", output_filepath)); + fail_if(!_files_compare(PACKAGE_DATA_DIR"/data/docs_ref.h", output_filepath)); + remove(output_filepath); + fail_if(0 != _eolian_gen_execute(PACKAGE_DATA_DIR"/data/docs.eo", "--legacy --gh", output_filepath)); + fail_if(!_files_compare(PACKAGE_DATA_DIR"/data/docs_ref_legacy.h", output_filepath)); +} +END_TEST + void eolian_generation_test(TCase *tc) { tcase_add_test(tc, eolian_types_generation); @@ -200,5 +219,6 @@ void eolian_generation_test(TCase *tc) tcase_add_test(tc, eolian_dev_impl_code); tcase_add_test(tc, eolian_functions_descriptions); tcase_add_test(tc, eolian_import); + tcase_add_test(tc, eolian_docs); } diff --git a/src/tests/eolian/eolian_parsing.c b/src/tests/eolian/eolian_parsing.c index fa6681a2af..bdfbedb1ac 100644 --- a/src/tests/eolian/eolian_parsing.c +++ b/src/tests/eolian/eolian_parsing.c @@ -1199,7 +1199,9 @@ START_TEST(eolian_docs) fail_if(strcmp(eolian_documentation_summary_get(doc), "Docs for class.")); fail_if(strcmp(eolian_documentation_description_get(doc), - "More docs for class. @Docs.prop. @Foo @Bar @Alias @pants")); + "More docs for class. Testing references now. " + "@Foo @Bar @Alias @pants @Docs.meth @Docs.prop " + "@Docs.prop.get @Docs.prop.set @Foo.field1 @Bar.foo @Docs")); fail_if(!(fid = eolian_class_function_get_by_name(class, "meth", EOLIAN_METHOD))); fail_if(!(doc = eolian_function_documentation_get(fid, EOLIAN_METHOD)));