diff options
Diffstat (limited to 'scripts/gen_vimdoc.py')
-rwxr-xr-x | scripts/gen_vimdoc.py | 274 |
1 files changed, 164 insertions, 110 deletions
diff --git a/scripts/gen_vimdoc.py b/scripts/gen_vimdoc.py index cdcab817ad..6f7b9d6737 100755 --- a/scripts/gen_vimdoc.py +++ b/scripts/gen_vimdoc.py @@ -48,26 +48,50 @@ DEBUG = ('DEBUG' in os.environ) INCLUDE_C_DECL = ('INCLUDE_C_DECL' in os.environ) INCLUDE_DEPRECATED = ('INCLUDE_DEPRECATED' in os.environ) -doc_filename = 'api.txt' -# String used to find the start of the generated part of the doc. -section_start_token = '*api-global*' -# Required prefix for API function names. -api_func_name_prefix = 'nvim_' - +text_width = 78 +script_path = os.path.abspath(__file__) +base_dir = os.path.dirname(os.path.dirname(script_path)) +out_dir = os.path.join(base_dir, 'tmp-{mode}-doc') +filter_cmd = '%s %s' % (sys.executable, script_path) +seen_funcs = set() +lua2dox_filter = os.path.join(base_dir, 'scripts', 'lua2dox_filter') + +CONFIG = { + 'api': { + 'filename': 'api.txt', + # String used to find the start of the generated part of the doc. + 'section_start_token': '*api-global*', + # Section ordering. + 'section_order' : [ + 'vim.c', + 'buffer.c', + 'window.c', + 'tabpage.c', + 'ui.c', + ], + # List of files/directories for doxygen to read, separated by blanks + 'files': os.path.join(base_dir, 'src/nvim/api'), + # file patterns used by doxygen + 'file_patterns': '*.h *.c', + # Only function with this prefix are considered + 'func_name_prefix': 'nvim_', + }, + 'lua': { + 'filename': 'if_lua.txt', + 'section_start_token': '*vim-lua*', + 'section_order' : [ + 'vim.lua', + ], + 'files': os.path.join(base_dir, 'src/nvim/lua/vim.lua'), + 'file_patterns': '*.lua', + 'func_name_prefix': '', + } +} # Section name overrides. section_name = { 'vim.c': 'Global', } -# Section ordering. -section_order = ( - 'vim.c', - 'buffer.c', - 'window.c', - 'tabpage.c', - 'ui.c', -) - param_exclude = ( 'channel_id', ) @@ -77,13 +101,6 @@ annotation_map = { 'FUNC_API_ASYNC': '{async}', } -text_width = 78 -script_path = os.path.abspath(__file__) -base_dir = os.path.dirname(os.path.dirname(script_path)) -src_dir = os.path.join(base_dir, 'src/nvim/api') -out_dir = os.path.join(base_dir, 'tmp-api-doc') -filter_cmd = '%s %s' % (sys.executable, script_path) -seen_funcs = set() # Tracks `xrefsect` titles. As of this writing, used only for separating # deprecated functions. @@ -400,7 +417,7 @@ def parse_parblock(parent, prefix='', width=62, indent=''): # }}} -def parse_source_xml(filename): +def parse_source_xml(filename, mode): """Collects API functions. Returns two strings: @@ -415,9 +432,12 @@ def parse_source_xml(filename): deprecated_functions = [] dom = minidom.parse(filename) + compoundname = get_text(dom.getElementsByTagName('compoundname')[0]) for member in dom.getElementsByTagName('memberdef'): if member.getAttribute('static') == 'yes' or \ - member.getAttribute('kind') != 'function': + member.getAttribute('kind') != 'function' or \ + member.getAttribute('prot') == 'private' or \ + get_text(get_child(member, 'name')).startswith('_'): continue loc = find_first(member, 'location') @@ -444,7 +464,12 @@ def parse_source_xml(filename): annotations = filter(None, map(lambda x: annotation_map.get(x), annotations.split())) - vimtag = '*{}()*'.format(name) + if mode == 'lua': + fstem = compoundname.split('.')[0] + vimtag = '*%s.%s()*' % (fstem, name) + else: + vimtag = '*%s()*' % name + params = [] type_length = 0 @@ -454,6 +479,10 @@ def parse_source_xml(filename): declname = get_child(param, 'declname') if declname: param_name = get_text(declname).strip() + elif mode == 'lua': + # that's how it comes out of lua2dox + param_name = param_type + param_type = '' if param_name in param_exclude: continue @@ -521,7 +550,7 @@ def parse_source_xml(filename): if 'Deprecated' in xrefs: deprecated_functions.append(func_doc) - elif name.startswith(api_func_name_prefix): + elif name.startswith(CONFIG[mode]['func_name_prefix']): functions.append(func_doc) xrefs.clear() @@ -547,115 +576,138 @@ def gen_docs(config): Doxygen is called and configured through stdin. """ - p = subprocess.Popen(['doxygen', '-'], stdin=subprocess.PIPE) - p.communicate(config.format(input=src_dir, output=out_dir, - filter=filter_cmd).encode('utf8')) - if p.returncode: - sys.exit(p.returncode) - - sections = {} - intros = {} - sep = '=' * text_width - - base = os.path.join(out_dir, 'xml') - dom = minidom.parse(os.path.join(base, 'index.xml')) - - # generate docs for section intros - for compound in dom.getElementsByTagName('compound'): - if compound.getAttribute('kind') != 'group': - continue + for mode in CONFIG: + output_dir = out_dir.format(mode=mode) + p = subprocess.Popen(['doxygen', '-'], stdin=subprocess.PIPE) + p.communicate( + config.format( + input=CONFIG[mode]['files'], + output=output_dir, + filter=filter_cmd, + file_patterns=CONFIG[mode]['file_patterns']) + .encode('utf8') + ) + if p.returncode: + sys.exit(p.returncode) + + sections = {} + intros = {} + sep = '=' * text_width + + base = os.path.join(output_dir, 'xml') + dom = minidom.parse(os.path.join(base, 'index.xml')) + + # generate docs for section intros + for compound in dom.getElementsByTagName('compound'): + if compound.getAttribute('kind') != 'group': + continue - groupname = get_text(find_first(compound, 'name')) - groupxml = os.path.join(base, '%s.xml' % compound.getAttribute('refid')) + groupname = get_text(find_first(compound, 'name')) + groupxml = os.path.join(base, '%s.xml' % compound.getAttribute('refid')) - desc = find_first(minidom.parse(groupxml), 'detaileddescription') - if desc: - doc = parse_parblock(desc) - if doc: - intros[groupname] = doc + desc = find_first(minidom.parse(groupxml), 'detaileddescription') + if desc: + doc = parse_parblock(desc) + if doc: + intros[groupname] = doc - for compound in dom.getElementsByTagName('compound'): - if compound.getAttribute('kind') != 'file': - continue + for compound in dom.getElementsByTagName('compound'): + if compound.getAttribute('kind') != 'file': + continue - filename = get_text(find_first(compound, 'name')) - if filename.endswith('.c'): - functions, deprecated = parse_source_xml( - os.path.join(base, '%s.xml' % compound.getAttribute('refid'))) + filename = get_text(find_first(compound, 'name')) + if filename.endswith('.c') or filename.endswith('.lua'): + functions, deprecated = parse_source_xml( + os.path.join(base, '%s.xml' % + compound.getAttribute('refid')), mode) - if not functions and not deprecated: - continue + if not functions and not deprecated: + continue - if functions or deprecated: - name = os.path.splitext(os.path.basename(filename))[0] - if name == 'ui': - name = name.upper() - else: - name = name.title() + if functions or deprecated: + name = os.path.splitext(os.path.basename(filename))[0] + if name == 'ui': + name = name.upper() + else: + name = name.title() - doc = '' + doc = '' - intro = intros.get('api-%s' % name.lower()) - if intro: - doc += '\n\n' + intro + intro = intros.get('api-%s' % name.lower()) + if intro: + doc += '\n\n' + intro - if functions: - doc += '\n\n' + functions + if functions: + doc += '\n\n' + functions - if INCLUDE_DEPRECATED and deprecated: - doc += '\n\n\nDeprecated %s Functions: ~\n\n' % name - doc += deprecated + if INCLUDE_DEPRECATED and deprecated: + doc += '\n\n\nDeprecated %s Functions: ~\n\n' % name + doc += deprecated - if doc: - filename = os.path.basename(filename) - name = section_name.get(filename, name) - title = '%s Functions' % name - helptag = '*api-%s*' % name.lower() - sections[filename] = (title, helptag, doc) + if doc: + filename = os.path.basename(filename) + name = section_name.get(filename, name) - if not sections: - return + if mode == 'lua': + title = '%s Lua Functions' % name + helptag = '*%s-lua*' % name.lower() + else: + title = '%s Functions' % name + helptag = '*api-%s*' % name.lower() + sections[filename] = (title, helptag, doc) - docs = '' + if not sections: + return - i = 0 - for filename in section_order: - if filename not in sections: - continue - title, helptag, section_doc = sections.pop(filename) + docs = '' - i += 1 - docs += sep - docs += '\n%s%s' % (title, helptag.rjust(text_width - len(title))) - docs += section_doc - docs += '\n\n\n' + i = 0 + for filename in CONFIG[mode]['section_order']: + if filename not in sections: + continue + title, helptag, section_doc = sections.pop(filename) - if sections: - # In case new API sources are added without updating the order dict. - for title, helptag, section_doc in sections.values(): i += 1 docs += sep docs += '\n%s%s' % (title, helptag.rjust(text_width - len(title))) docs += section_doc docs += '\n\n\n' - docs = docs.rstrip() + '\n\n' - docs += ' vim:tw=78:ts=8:ft=help:norl:\n' + if sections: + # In case new API sources are added without updating the order dict. + for title, helptag, section_doc in sections.values(): + i += 1 + docs += sep + docs += '\n%s%s' % (title, helptag.rjust(text_width - len(title))) + docs += section_doc + docs += '\n\n\n' - doc_file = os.path.join(base_dir, 'runtime/doc', doc_filename) - delete_lines_below(doc_file, section_start_token) - with open(doc_file, 'ab') as fp: - fp.write(docs.encode('utf8')) - shutil.rmtree(out_dir) + docs = docs.rstrip() + '\n\n' + docs += ' vim:tw=78:ts=8:ft=help:norl:\n' + + doc_file = os.path.join(base_dir, 'runtime', 'doc', + CONFIG[mode]['filename']) + + delete_lines_below(doc_file, CONFIG[mode]['section_start_token']) + with open(doc_file, 'ab') as fp: + fp.write(docs.encode('utf8')) + + shutil.rmtree(output_dir) def filter_source(filename): - """Filters the source to fix macros that confuse Doxygen.""" - with open(filename, 'rt') as fp: - print(re.sub(r'^(ArrayOf|DictionaryOf)(\(.*?\))', - lambda m: m.group(1)+'_'.join( - re.split(r'[^\w]+', m.group(2))), - fp.read(), flags=re.M)) + name, extension = os.path.splitext(filename) + if extension == '.lua': + p = subprocess.run([lua2dox_filter, filename], stdout=subprocess.PIPE) + op = ('?' if 0 != p.returncode else p.stdout.decode('utf-8')) + print(op) + else: + """Filters the source to fix macros that confuse Doxygen.""" + with open(filename, 'rt') as fp: + print(re.sub(r'^(ArrayOf|DictionaryOf)(\(.*?\))', + lambda m: m.group(1)+'_'.join( + re.split(r'[^\w]+', m.group(2))), + fp.read(), flags=re.M)) # Doxygen Config {{{ @@ -663,13 +715,15 @@ Doxyfile = ''' OUTPUT_DIRECTORY = {output} INPUT = {input} INPUT_ENCODING = UTF-8 -FILE_PATTERNS = *.h *.c +FILE_PATTERNS = {file_patterns} RECURSIVE = YES INPUT_FILTER = "{filter}" EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = */private/* EXCLUDE_SYMBOLS = +EXTENSION_MAPPING = lua=C +EXTRACT_PRIVATE = NO GENERATE_HTML = NO GENERATE_DOCSET = NO |