summaryrefslogtreecommitdiff
path: root/src/bin
diff options
context:
space:
mode:
authorXavi Artigas <xavierartigas@yahoo.es>2019-04-11 10:38:40 +0200
committerXavi Artigas <xavierartigas@yahoo.es>2019-04-11 10:39:09 +0200
commit04a41a37127e4491428ebce70689c180cb12418a (patch)
treecd01ce9d12e85c69676648d02dafddf6985fd251 /src/bin
parent748070125ff43c001feb8e191cf2be8d0f59d01d (diff)
mono-docs: Allow embedding external examples
Summary: New option added to eolian_gen: -e <dir> This specifies a directory to search for examples. If a file is found with the same name as an EFL C# class (e.g. Efl.Ui.Button.cs) or as an EFL C# method or property (e.g. Efl.IText.Text.cs, Efl.IText.SetText.cs) its full contents will be embedded in the documentation for that class or method within <example> and <code> tags. This is, in turn, is parsed by DocFX and shown in Example boxes in the generated pages. If an example file is not found, no examples are embedded for that object. If -e is not used, no examples are embedded for any object. New option added to meson: mono-examples-dir to point to the examples directory. This directory is then passed to eolian_mono through -e. Do not use it (or define it to nothing) to disable example embedding. No performance drop has been observed because of these extra tests. Right now examples can only be given for base classes, not for derived ones (i.e. Efl.IText.Text but not Efl.Ui.Button.Text). This will be addressed in a later commit. Feature Depends on D8587 Test Plan: Create an examples folder and put some files in it: ``` mkdir /tmp/examples echo 'var button = new Efl.Ui.Button();' > /tmp/examples/Efl.Ui.Button.cs echo 'button.AutoRepeatEnabled = true;' > /tmp/examples/Efl.Ui.IAutorepeat.AutorepeatEnabled.cs echo 'button.SetAutoRepeatEnabled(true);' > /tmp/examples/Efl.Ui.IAutorepeat.SetAutorepeatEnabled.cs ``` Configure meson to embed examples and build: ``` meson configure -Dmono-examples-dir=/tmp/examples ninja ``` Examine the generated efl_ui_button.eo.cs file to see embedded <example> tags, or run DocFX and bask in the glory of documentation pages with examples: ``` cd doc/docfx ./gendoc.sh ``` Reviewers: lauromoura, felipealmeida, vitor.sousa, zmike, bu5hm4n Reviewed By: vitor.sousa Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D8592
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/eolian_mono/eolian/mono/documentation.hh34
-rw-r--r--src/bin/eolian_mono/eolian/mono/generation_contexts.hh1
-rw-r--r--src/bin/eolian_mono/eolian_mono.cc13
3 files changed, 40 insertions, 8 deletions
diff --git a/src/bin/eolian_mono/eolian/mono/documentation.hh b/src/bin/eolian_mono/eolian/mono/documentation.hh
index c46cbd4231..0460b5783e 100644
--- a/src/bin/eolian_mono/eolian/mono/documentation.hh
+++ b/src/bin/eolian_mono/eolian/mono/documentation.hh
@@ -313,12 +313,22 @@ struct documentation_generator
313 } 313 }
314 314
315 template<typename OutputIterator, typename Context> 315 template<typename OutputIterator, typename Context>
316 bool generate_tag_example(OutputIterator sink, std::string const& example, Context const& context) const 316 bool generate_tag_example(OutputIterator sink, std::string const& object_name, Context const& context) const
317 { 317 {
318 auto options = efl::eolian::grammar::context_find_tag<options_context>(context);
319 // Example embedding not requested
320 if (options.examples_dir.empty()) return true;
321 std::string file_name = options.examples_dir + object_name + ".cs";
322 std::ifstream exfile(file_name);
323 // There is no example file for this class or method, just return
324 if (!exfile.good()) return true;
325 std::stringstream example_buff;
326 example_buff << exfile.rdbuf();
327
318 if (!as_generator(scope_tab(scope_size) << "/// ").generate(sink, attributes::unused, context)) return false; 328 if (!as_generator(scope_tab(scope_size) << "/// ").generate(sink, attributes::unused, context)) return false;
319 if (!generate_opening_tag(sink, "example", context)) return false; 329 if (!generate_opening_tag(sink, "example", context)) return false;
320 if (!generate_opening_tag(sink, "code", context)) return false; 330 if (!generate_opening_tag(sink, "code", context)) return false;
321 if (!generate_escaped_content(sink, example, context)) return false; 331 if (!generate_escaped_content(sink, example_buff.str(), context)) return false;
322 if (!generate_closing_tag(sink, "code", context)) return false; 332 if (!generate_closing_tag(sink, "code", context)) return false;
323 if (!generate_closing_tag(sink, "example", context)) return false; 333 if (!generate_closing_tag(sink, "example", context)) return false;
324 return as_generator("\n").generate(sink, attributes::unused, context); 334 return as_generator("\n").generate(sink, attributes::unused, context);
@@ -332,6 +342,15 @@ struct documentation_generator
332 } 342 }
333 343
334 template<typename OutputIterator, typename Context> 344 template<typename OutputIterator, typename Context>
345 bool generate(OutputIterator sink, attributes::klass_def const& klass, Context const& context) const
346 {
347 if (!generate(sink, klass.documentation, context)) return false;
348
349 std::string klass_name = name_helpers::klass_full_concrete_or_interface_name(klass);
350 return generate_tag_example(sink, klass_name, context);
351 }
352
353 template<typename OutputIterator, typename Context>
335 bool generate(OutputIterator sink, attributes::property_def const& prop, Context const& context) const 354 bool generate(OutputIterator sink, attributes::property_def const& prop, Context const& context) const
336 { 355 {
337 if (!generate(sink, prop.documentation, context)) 356 if (!generate(sink, prop.documentation, context))
@@ -343,9 +362,12 @@ struct documentation_generator
343 else if (prop.getter.is_engaged()) 362 else if (prop.getter.is_engaged())
344 text = prop.getter->return_documentation.full_text; 363 text = prop.getter->return_documentation.full_text;
345 // If there are no docs at all, do not generate <value> tag 364 // If there are no docs at all, do not generate <value> tag
346 else return true; 365 if (!text.empty())
366 if (!generate_tag_value(sink, text, context)) return false;
347 367
348 return generate_tag_value(sink, text, context); 368 std::string managed_name = name_helpers::klass_full_concrete_or_interface_name(prop.klass);
369 managed_name += "." + name_helpers::property_managed_name(prop);
370 return generate_tag_example(sink, managed_name, context);
349 } 371 }
350 372
351 template<typename OutputIterator, typename Context> 373 template<typename OutputIterator, typename Context>
@@ -381,7 +403,7 @@ struct documentation_generator
381 if (!generate_tag_return(sink, func.return_documentation.full_text, context)) 403 if (!generate_tag_return(sink, func.return_documentation.full_text, context))
382 return false; 404 return false;
383 405
384 return true; 406 return generate_tag_example(sink, function_conversion(func), context);
385 } 407 }
386 408
387 template<typename OutputIterator, typename Context> 409 template<typename OutputIterator, typename Context>
@@ -397,7 +419,7 @@ struct documentation_generator
397 if (!generate_tag_return(sink, func.return_documentation.full_text, context)) 419 if (!generate_tag_return(sink, func.return_documentation.full_text, context))
398 return false; 420 return false;
399 421
400 return true; 422 return generate_tag_example(sink, function_conversion(func), context);
401 } 423 }
402 424
403 template<typename OutputIterator, typename Context> 425 template<typename OutputIterator, typename Context>
diff --git a/src/bin/eolian_mono/eolian/mono/generation_contexts.hh b/src/bin/eolian_mono/eolian/mono/generation_contexts.hh
index 25ac3098fb..ff6c0391ba 100644
--- a/src/bin/eolian_mono/eolian/mono/generation_contexts.hh
+++ b/src/bin/eolian_mono/eolian/mono/generation_contexts.hh
@@ -78,6 +78,7 @@ struct eolian_state_context {
78 78
79struct options_context { 79struct options_context {
80 bool want_beta; 80 bool want_beta;
81 std::string examples_dir;
81}; 82};
82 83
83} 84}
diff --git a/src/bin/eolian_mono/eolian_mono.cc b/src/bin/eolian_mono/eolian_mono.cc
index 0fcc63fa42..8f24f762f0 100644
--- a/src/bin/eolian_mono/eolian_mono.cc
+++ b/src/bin/eolian_mono/eolian_mono.cc
@@ -43,6 +43,7 @@ struct options_type
43 std::vector<std::string> include_dirs; 43 std::vector<std::string> include_dirs;
44 std::string in_file; 44 std::string in_file;
45 std::string out_file; 45 std::string out_file;
46 std::string examples_dir;
46 std::string dllimport; 47 std::string dllimport;
47 mutable Eolian_State* state; 48 mutable Eolian_State* state;
48 mutable Eolian_Unit const* unit; 49 mutable Eolian_Unit const* unit;
@@ -145,7 +146,8 @@ run(options_type const& opts)
145 146
146 auto context = context_add_tag(eolian_mono::indentation_context{0}, 147 auto context = context_add_tag(eolian_mono::indentation_context{0},
147 context_add_tag(eolian_mono::eolian_state_context{opts.state}, 148 context_add_tag(eolian_mono::eolian_state_context{opts.state},
148 context_add_tag(eolian_mono::options_context{opts.want_beta}, 149 context_add_tag(eolian_mono::options_context{opts.want_beta,
150 opts.examples_dir},
149 context_add_tag(eolian_mono::library_context{opts.dllimport, 151 context_add_tag(eolian_mono::library_context{opts.dllimport,
150 opts.v_major, 152 opts.v_major,
151 opts.v_minor, 153 opts.v_minor,
@@ -294,6 +296,7 @@ _usage(const char *progname)
294 << " -r, --recurse Recurse input directories loading .eo files." << std::endl 296 << " -r, --recurse Recurse input directories loading .eo files." << std::endl
295 << " -v, --version Print the version." << std::endl 297 << " -v, --version Print the version." << std::endl
296 << " -b, --beta Enable @beta methods." << std::endl 298 << " -b, --beta Enable @beta methods." << std::endl
299 << " -e, --example-dir <dir> Folder to search for example files." << std::endl
297 << " -h, --help Print this help." << std::endl; 300 << " -h, --help Print this help." << std::endl;
298 exit(EXIT_FAILURE); 301 exit(EXIT_FAILURE);
299} 302}
@@ -324,9 +327,10 @@ opts_get(int argc, char **argv)
324 { "vmin", required_argument, 0, 'm' }, 327 { "vmin", required_argument, 0, 'm' },
325 { "references", required_argument, 0, 'r'}, 328 { "references", required_argument, 0, 'r'},
326 { "beta", no_argument, 0, 'b'}, 329 { "beta", no_argument, 0, 'b'},
330 { "example-dir", required_argument, 0, 'e' },
327 { 0, 0, 0, 0 } 331 { 0, 0, 0, 0 }
328 }; 332 };
329 const char* options = "I:D:o:c:M:m:ar:vhb"; 333 const char* options = "I:D:o:c:M:m:ar:vhbe:";
330 334
331 int c, idx; 335 int c, idx;
332 while ( (c = getopt_long(argc, argv, options, long_options, &idx)) != -1) 336 while ( (c = getopt_long(argc, argv, options, long_options, &idx)) != -1)
@@ -382,6 +386,11 @@ opts_get(int argc, char **argv)
382 { 386 {
383 opts.want_beta = true; 387 opts.want_beta = true;
384 } 388 }
389 else if (c == 'e')
390 {
391 opts.examples_dir = optarg;
392 if (!opts.examples_dir.empty() && opts.examples_dir.back() != '/') opts.examples_dir += "/";
393 }
385 } 394 }
386 if (optind == argc-1) 395 if (optind == argc-1)
387 { 396 {