From 2f69ba27d3438f811f0e5d79562c5f96a2a3f69d Mon Sep 17 00:00:00 2001 From: Dave Andreoli Date: Wed, 3 Jan 2018 16:18:58 +0100 Subject: [PATCH] Put in a new (experimental) doc generator built only by templates This is (in my mind) meant to replace the current elua generator. Currently the generated output is pratically identical to the elua one, just some little difference here and there, some for thecnical reasons and some just for my preference. I consider this work just a starting point, extending the templates we can now easily improve our docs. Whithout the need to touch a single line of code. Really I think this is a great improvements, and this are some numbers to prove it: Current elua implementation: 4185 lines of code in 7 lua files generation time: ~ 7 seconds New generator: 115 lines of python + 513 lines of templates generation time: ~ 8 seconds (can be optimizd ALOT) To generate the full Efl.* docs just run "./gendoc.py -v" in this folder. ...will wait for reviews (in particular from @andy and @q66) --- src/scripts/gendoc/doc_alias.template | 24 +++ src/scripts/gendoc/doc_class.template | 106 +++++++++++ src/scripts/gendoc/doc_enum.template | 39 ++++ src/scripts/gendoc/doc_macros.include | 253 +++++++++++++++++++++++++ src/scripts/gendoc/doc_start.template | 52 +++++ src/scripts/gendoc/doc_struct.template | 39 ++++ src/scripts/gendoc/gendoc.py | 115 +++++++++++ 7 files changed, 628 insertions(+) create mode 100644 src/scripts/gendoc/doc_alias.template create mode 100644 src/scripts/gendoc/doc_class.template create mode 100644 src/scripts/gendoc/doc_enum.template create mode 100644 src/scripts/gendoc/doc_macros.include create mode 100644 src/scripts/gendoc/doc_start.template create mode 100644 src/scripts/gendoc/doc_struct.template create mode 100755 src/scripts/gendoc/gendoc.py diff --git a/src/scripts/gendoc/doc_alias.template b/src/scripts/gendoc/doc_alias.template new file mode 100644 index 0000000000..c0d5fa7a3d --- /dev/null +++ b/src/scripts/gendoc/doc_alias.template @@ -0,0 +1,24 @@ +doc_macros.include#! +~~Title: ${alias.full_name}$~~ +====== ${alias.full_name}$ (alias) ====== + +${BEST_SUMMARY(obj=alias)}$ + +${BEST_DESCRIPTION(obj=alias)}$ + +${BEST_SINCE(obj=alias)}$ + +${OBJECT_STATIC_CONTENT(obj=alias, section='description')}$ + +===== Signature ===== + + +TODO + + +===== C signature ===== + + +TODO + + diff --git a/src/scripts/gendoc/doc_class.template b/src/scripts/gendoc/doc_class.template new file mode 100644 index 0000000000..60f6779af1 --- /dev/null +++ b/src/scripts/gendoc/doc_class.template @@ -0,0 +1,106 @@ +doc_macros.include#! +~~Title: ${cls.full_name}$~~ +====== ${cls.full_name}$ (${CLS_TYPE}$) ====== + +${BEST_SUMMARY(obj=cls)}$ + +${BEST_DESCRIPTION(obj=cls)}$ + +${BEST_SINCE(obj=cls)}$ + +${OBJECT_STATIC_CONTENT(obj=cls, section='description')}$ + + +===== Inheritance ===== + + + => ${CLS_LINK(cls=inherit)}$#! + + +++++ Full hierarchy | + + + * ${CLS_LINK(cls=inherit)}$ //(${CLS_TYPE(cls=inherit)}$)// + + * ${CLS_LINK(cls=inherit)}$ //(${CLS_TYPE(cls=inherit)}$)// + + * ${CLS_LINK(cls=inherit)}$ //(${CLS_TYPE(cls=inherit)}$)// + + * ${CLS_LINK(cls=inherit)}$ //(${CLS_TYPE(cls=inherit)}$)// + + * ${CLS_LINK(cls=inherit)}$ //(${CLS_TYPE(cls=inherit)}$)// + + * ${CLS_LINK(cls=inherit)}$ //(${CLS_TYPE(cls=inherit)}$)// + + * ${CLS_LINK(cls=inherit)}$ //(${CLS_TYPE(cls=inherit)}$)// + + * ${CLS_LINK(cls=inherit)}$ //(${CLS_TYPE(cls=inherit)}$)// + + * ${CLS_LINK(cls=inherit)}$ //(${CLS_TYPE(cls=inherit)}$)// + + * ${CLS_LINK(cls=inherit)}$ //(${CLS_TYPE(cls=inherit)}$)// + + + + + + + + + + + +++++ + + +===== Properties ===== + + + +${IMPLEMENT_FULL(impl=impl, cls=cls)}$ +\\ + + +No properties defined in this class. + + +===== Methods ===== + + + +${IMPLEMENT_FULL(impl=impl, cls=cls)}$ +\\ + + +No Methods defined in this class. + + +===== Inherited members ===== + + +^ ${CLS_LINK(cls=cls2)}$ //(${CLS_TYPE(cls=cls2)}$)//^^^ + +| ${FUNC_SCOPE(func=impl.function)}$ #! +| **${FUNC_LINK(func=impl.function)}$** #! +| ${BEST_SUMMARY(obj=impl)}$ | + + +No inherits defined in this class. + + +===== Events ===== + + + +^ Local implemented ^^ event info ^ + +| ''${ev.name}$'' | ${BEST_SUMMARY(obj=ev)}$ ${OBJECT_SCOPE(obj=ev)}$ ${EVENT_TAGS}$| ${TYPE_LINK(type=ev.type) if ev.type else 'None'}$ | + + + + +^ Inherited from ${CLS_LINK(cls=cls2)}$ //(${CLS_TYPE(cls=cls2)}$)// ^^ event info ^ + +| ''${ev.name}$'' | ${BEST_SUMMARY(obj=ev)}$ ${OBJECT_SCOPE(obj=ev)}$ ${EVENT_TAGS}$ | ${TYPE_LINK(type=ev.type) if ev.type else 'None'}$ | + + diff --git a/src/scripts/gendoc/doc_enum.template b/src/scripts/gendoc/doc_enum.template new file mode 100644 index 0000000000..03f6cd62cd --- /dev/null +++ b/src/scripts/gendoc/doc_enum.template @@ -0,0 +1,39 @@ +doc_macros.include#! +~~Title: ${enum.full_name}$~~ +====== ${enum.full_name}$ (enum) ====== + +${BEST_SUMMARY(obj=enum)}$ + +${BEST_DESCRIPTION(obj=enum)}$ + +${BEST_SINCE(obj=enum)}$ + +${OBJECT_STATIC_CONTENT(obj=enum, section='description')}$ + +===== Fields ===== + +${OBJECT_STATIC_CONTENT(obj=enum, section='fields')}$ + + + * **${field.name}$** - ${BEST_SUMMARY(obj=field)}$ + + +===== Signature ===== + + +enum { + + ${field.name}$: ${field.value.serialize}$, + +} + + +===== C Signature ===== + + +typedef enum { + + ${field.c_name}$ = ${field.value.serialize}$, + +} ${enum.full_name.replace('.', '_')}$; + diff --git a/src/scripts/gendoc/doc_macros.include b/src/scripts/gendoc/doc_macros.include new file mode 100644 index 0000000000..ac01b99722 --- /dev/null +++ b/src/scripts/gendoc/doc_macros.include @@ -0,0 +1,253 @@ +#!############################################################################## +#!#### BEST_SUMMARY(obj) ##################################################### +#!############################################################################## + + + +${UNTOKENIZE(tokens=obj.documentation_get(obj.function.type).summary_tokens)}$#! + + + + +${UNTOKENIZE(tokens=parent_impl.documentation_get(parent_impl.function.type).summary_tokens)}$#! + + + + + +${UNTOKENIZE(tokens=obj.documentation.summary_tokens)}$#! + +**MISSING DOCS !!!!!**#! + + +#!############################################################################## +#!#### BEST_DESCRIPTION(obj) ################################################# +#!############################################################################## + + + +${UNTOKENIZE(tokens=obj.documentation_get(obj.function.type).description_tokens)}$#! + + + + +${UNTOKENIZE(tokens=parent_impl.documentation_get(parent_impl.function.type).description_tokens)}$#! + + + + + +${UNTOKENIZE(tokens=obj.documentation.description_tokens)}$#! + +**MISSING DOCS !!!!!**#! + + +#!############################################################################## +#!#### BEST_SINCE(obj) ####################################################### +#!############################################################################## + + +//Since ${obj.documentation.since}$// + + +#!############################################################################## +#!#### UNTOKENIZE(tokens) #################################################### +#!############################################################################## + + +${'\n\n' if i else ''}$#! + + +%%${token.text}$%%#! + +**REF ${token.text}$ ${token.ref}$ ??**#! + +''${token.text}$''#! + + +${token.text}$ + + + +${token.text}$ + + + +${token.text}$ + + + +**TODO:** ${token.text}$ + + +**USUPPORTED TOKEN TYPE ${token}$** + + + + +#!############################################################################## +#!#### CLS_TYPE(cls) ######################################################### +#!############################################################################## + + +class#! + +class#! + +mixin#! + +interface#! + + +#!############################################################################## +#!#### CLS_LINK(cls) ######################################################### +#!############################################################################## + +[[:develop:api#! + +:${n.lower()}$#! + +:${cls.name.lower()}$|${cls.full_name}$]] + +#!############################################################################## +#!#### EVENT_LINK(cls, ev) ################################################### +#!############################################################################## + +[[:develop:api#! + +:${n.lower()}$#! + +:${cls.name.lower()}$#! +:event#! +:${ev.name.lower().replace(',','_')}$|${ev.name}$]] + +#!############################################################################## +#!#### TYPEDECL_LINK(typedecl) ############################################### +#!############################################################################## + +[[:develop:api#! + +:${n.lower()}$#! + +:${typedecl.name.lower()}$|${typedecl.full_name}$]] + +#!############################################################################## +#!#### TYPE_LINK(type) ####################################################### +#!############################################################################## + +[[:develop:api#! + +:${n.lower()}$#! + +:${type.name.lower()}$|${type.full_name}$]] + +#!############################################################################## +#!#### FUNC_LINK(func) ####################################################### +#!############################################################################## + +[[:develop:api#! + +:${n.lower()}$#! + + +:method#! + +:property#! + +:${func.name}$|${func.name}$]] + +#!############################################################################## +#!#### FUNC_SCOPE(func) ###################################################### +#!############################################################################## + + + ''class method'' #! + + + + ''protected get'' #! + + ''private get'' #! + + + ''protected set'' #! + + ''private set'' #! + + + + ''protected'' #! + + ''private'' #! + + + +#!############################################################################## +#!#### OBJECT_SCOPE(obj) ##################################################### +#!############################################################################## + + + ''private'' #! + + ''protected'' #! + + +#!############################################################################## +#!#### EVENT_TAGS(ev) ######################################################## +#!############################################################################## + + + ''hot'' #! + + ''restart'' #! + + +#!############################################################################## +#!#### IMPLEMENT_FULL(impl, cls) ############################################# +#!############################################################################## + +**${FUNC_LINK(func=impl.function)}$** #! +(#! + + +${', ' if i else ''}$${val.type.name}$#! + + + +${', ' if i else ''}$#! +//${param.type.name}$// ''${param.direction.name.lower()}$'' **${param.name}$**#! + + +)#! + + ''rw'' #! + + ''read only'' #! + + ''write only'' #! + + + => //${impl.function.method_return_type.name}$// #! + + => //None// #! + + +${FUNC_SCOPE(func=impl.function)}$#! + +//[Overridden from ${CLS_LINK(cls=impl.class_)}$]// #! + +\\ +> ${BEST_SUMMARY(obj=impl)}$ + +#!############################################################################## +#!#### OBJECT_STATIC_CONTENT(obj, section) ################################### +#!############################################################################## + +{{page>:develop:api-include#! + +:${ns.lower()}$#! + +:${obj.name.lower()}$#! +:{section}#! +&nouser&nolink&nodate}} + diff --git a/src/scripts/gendoc/doc_start.template b/src/scripts/gendoc/doc_start.template new file mode 100644 index 0000000000..640f805d9d --- /dev/null +++ b/src/scripts/gendoc/doc_start.template @@ -0,0 +1,52 @@ +doc_macros.include#! +~~Title: EFL Reference~~ +{{page>:develop:api-include:reference:general&nouser&nolink&nodate}} + + + +===== ${ns.name}$ ===== + + + +^ Classes ^^ + +| ${CLS_LINK}$ | ${BEST_SUMMARY(obj=cls)}$ | + +#! + + +^ Interfaces ^^ + +| ${CLS_LINK}$ | ${BEST_SUMMARY(obj=cls)}$ | + +#! + + +^ Mixins ^^ + +| ${CLS_LINK}$ | ${BEST_SUMMARY(obj=cls)}$ | + +#! + + +^ Aliases ^^ + +| ${TYPEDECL_LINK}$ | ${BEST_SUMMARY(obj=typedecl)}$ | + +#! + + +^ Structures ^^ + +| ${TYPEDECL_LINK}$ | ${BEST_SUMMARY(obj=typedecl)}$ | + +#! + + +^ Enumerations ^^ + +| ${TYPEDECL_LINK}$ | ${BEST_SUMMARY(obj=typedecl)}$ | + + + + diff --git a/src/scripts/gendoc/doc_struct.template b/src/scripts/gendoc/doc_struct.template new file mode 100644 index 0000000000..370e9be6e9 --- /dev/null +++ b/src/scripts/gendoc/doc_struct.template @@ -0,0 +1,39 @@ +doc_macros.include#! +~~Title: ${struct.full_name}$~~ +====== ${struct.full_name}$ (struct) ====== + +${BEST_SUMMARY(obj=struct)}$ + +${BEST_DESCRIPTION(obj=struct)}$ + +${BEST_SINCE(obj=struct)}$ + +${OBJECT_STATIC_CONTENT(obj=struct, section='description')}$ + +===== Fields ===== + +${OBJECT_STATIC_CONTENT(obj=struct, section='fields')}$ + + + * **${field.name}$** - ${BEST_SUMMARY(obj=field)}$ + + +===== Signature ===== + + +struct ${struct.full_name}$ { + + ${field.name}$: ${field.type.name}$, + +} + + +===== C Signature ===== + + +typedef struct _${struct.full_name.replace('.', '_')}$ { + + ${field.name}$: **TODO (issue with Typedecl.c_type need Unit)**, + +} ${struct.full_name.replace('.', '_')}$; + diff --git a/src/scripts/gendoc/gendoc.py b/src/scripts/gendoc/gendoc.py new file mode 100755 index 0000000000..394c641f44 --- /dev/null +++ b/src/scripts/gendoc/gendoc.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# encoding: utf-8 +""" +Efl documentation generator + +Use this script without arguments to generate the full documentation of the Efl +namespace in a folder called 'dokuwiki' (-v to see all generated files) + + --help to see all other options + +""" +import os +import sys +import argparse +import atexit + + +# Use .eo files from the source tree (not the installed ones) +script_path = os.path.dirname(os.path.realpath(__file__)) +root_path = os.path.abspath(os.path.join(script_path, '..', '..', '..')) +SCAN_FOLDER = os.path.join(root_path, 'src', 'lib') + + +# Use pyolian from source (not installed) +pyolian_path = os.path.join(root_path, 'src', 'scripts') +sys.path.insert(0, pyolian_path) +from pyolian import eolian +from pyolian.generator import Template + + +# parse args +parser = argparse.ArgumentParser(description='Pyolian DocuWiki generator.') +parser.add_argument('--root-path', '-r', metavar='FOLDER', default='dokuwiki', + help='where to write files to (root of dokuwiki) ' + 'default to: "./dokuwiki"') +parser.add_argument('--verbose', '-v', action='store_true', + help='print a line for each rendered file') +parser.add_argument('--namespace', '-n', metavar='ROOT', default='Efl', + help='root namespace of the docs. (default to "Efl")') +_choices = ['start', 'classes', 'enums', 'structs', 'aliases'] +parser.add_argument('--step', '-s', metavar='STEP', default=None, + choices=_choices, + help='A single step to run (default to all), ' + 'valid choises: '+ ', '.join(_choices)) +args = parser.parse_args() + + +# load the whole eolian db (from .eo files in source tree) +eolian_db = eolian.Eolian() +if not isinstance(eolian_db, eolian.Eolian): + raise(RuntimeError('Eolian, failed to create Eolian state')) + +if not eolian_db.directory_scan(SCAN_FOLDER): + raise(RuntimeError('Eolian, failed to scan source directory')) + +if not eolian_db.all_eot_files_parse(): + raise(RuntimeError('Eolian, failed to parse all EOT files')) + +if not eolian_db.all_eo_files_parse(): + raise(RuntimeError('Eolian, failed to parse all EO files')) + + +# cleanup the database on exit +def cleanup_db(): + global eolian_db + del eolian_db +atexit.register(cleanup_db) + + +# calculate the full path for the txt page of the given object +def page_path_for_object(obj): + path = ['data', 'pages', 'develop', 'api'] + for ns in obj.namespaces: + path.append(ns.lower()) + output_file = obj.name.lower() + '.txt' + return os.path.join(args.root_path, *path, output_file) + + +# render the main start.txt page +if args.step in ('start', None): + t = Template('doc_start.template') + output_file = os.path.join(args.root_path,'data','pages','develop','api','start.txt') + t.render(output_file, args.verbose, nspaces=eolian_db.all_namespaces) + +# render a page for each Class +if args.step in ('classes', None): + t = Template('doc_class.template') + for cls in eolian_db.all_classes: + if cls.full_name.startswith(args.namespace): + output_file = page_path_for_object(cls) + t.render(output_file, args.verbose, cls=cls.full_name) + +# render a page for each Enum +if args.step in ('enums', None): + t = Template('doc_enum.template') + for enum in eolian_db.typedecl_all_enums: + if enum.full_name.startswith(args.namespace): + output_file = page_path_for_object(enum) + t.render(output_file, args.verbose, enum=enum.full_name) + +# render a page for each Struct +if args.step in ('structs', None): + t = Template('doc_struct.template') + for struct in eolian_db.typedecl_all_structs: + if struct.full_name.startswith(args.namespace): + output_file = page_path_for_object(struct) + t.render(output_file, args.verbose, struct=struct.full_name) + +# render a page for each Alias +if args.step in ('aliases', None): + t = Template('doc_alias.template') + for alias in eolian_db.typedecl_all_aliases: + if alias.full_name.startswith(args.namespace): + output_file = page_path_for_object(alias) + t.render(output_file, args.verbose, alias=alias.full_name)