From a7ecff657cfbcc442bfc70d51efbad1b57a9be46 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 29 Dec 2020 16:29:00 +0900 Subject: [PATCH] Make doc generation work with sphinx v3.3 --- doc/_exts/sphinxcontrib/rubydomain.py | 2 +- doc/mkapiref.py | 148 ++++++++++++++++++-------- 2 files changed, 107 insertions(+), 43 deletions(-) diff --git a/doc/_exts/sphinxcontrib/rubydomain.py b/doc/_exts/sphinxcontrib/rubydomain.py index 157c4aa3..62a04285 100644 --- a/doc/_exts/sphinxcontrib/rubydomain.py +++ b/doc/_exts/sphinxcontrib/rubydomain.py @@ -18,7 +18,7 @@ from docutils.parsers.rst import Directive from sphinx import addnodes from sphinx import version_info from sphinx.roles import XRefRole -from sphinx.locale import l_, _ +from sphinx.locale import _ from sphinx.domains import Domain, ObjType, Index from sphinx.directives import ObjectDescription from sphinx.util.nodes import make_refnode diff --git a/doc/mkapiref.py b/doc/mkapiref.py index 6ed5fd73..3886a65f 100755 --- a/doc/mkapiref.py +++ b/doc/mkapiref.py @@ -1,9 +1,11 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # nghttp2 - HTTP/2 C Library - +# +# Copyright (c) 2020 nghttp2 contributors +# Copyright (c) 2020 ngtcp2 contributors # Copyright (c) 2012 Tatsuhiro Tsujikawa - +# # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including @@ -25,17 +27,16 @@ # Generates API reference from C source code. -from __future__ import unicode_literals -from __future__ import print_function # At least python 2.6 is required import re, sys, argparse, os.path class FunctionDoc: - def __init__(self, name, content, domain): + def __init__(self, name, content, domain, filename): self.name = name self.content = content self.domain = domain if self.domain == 'function': self.funcname = re.search(r'(nghttp2_[^ )]+)\(', self.name).group(1) + self.filename = filename def write(self, out): out.write('.. {}:: {}\n'.format(self.domain, self.name)) @@ -64,6 +65,26 @@ class StructDoc: out.write(' {}\n'.format(line)) out.write('\n') +class EnumDoc: + def __init__(self, name, content, members): + self.name = name + self.content = content + self.members = members + + def write(self, out): + if self.name: + out.write('.. type:: {}\n'.format(self.name)) + out.write('\n') + for line in self.content: + out.write(' {}\n'.format(line)) + out.write('\n') + for name, content in self.members: + out.write(' .. enum:: {}\n'.format(name)) + out.write('\n') + for line in content: + out.write(' {}\n'.format(line)) + out.write('\n') + class MacroDoc: def __init__(self, name, content): self.name = name @@ -75,50 +96,76 @@ class MacroDoc: for line in self.content: out.write(' {}\n'.format(line)) -def make_api_ref(infiles): +class MacroSectionDoc: + def __init__(self, content): + self.content = content + + def write(self, out): + out.write('\n') + c = ' '.join(self.content).strip() + out.write(c) + out.write('\n') + out.write('-' * len(c)) + out.write('\n\n') + +class TypedefDoc: + def __init__(self, name, content): + self.name = name + self.content = content + + def write(self, out): + out.write('''.. type:: {}\n'''.format(self.name)) + out.write('\n') + for line in self.content: + out.write(' {}\n'.format(line)) + +def make_api_ref(infile): macros = [] enums = [] types = [] functions = [] - for infile in infiles: - while True: + while True: + line = infile.readline() + if not line: + break + elif line == '/**\n': line = infile.readline() - if not line: - break - elif line == '/**\n': - line = infile.readline() - doctype = line.split()[1] - if doctype == '@function': - functions.append(process_function('function', infile)) - elif doctype == '@functypedef': - types.append(process_function('type', infile)) - elif doctype == '@struct' or doctype == '@union': - types.append(process_struct(infile)) - elif doctype == '@enum': - enums.append(process_enum(infile)) - elif doctype == '@macro': - macros.append(process_macro(infile)) + doctype = line.split()[1] + if doctype == '@function': + functions.append(process_function('function', infile)) + elif doctype == '@functypedef': + types.append(process_function('type', infile)) + elif doctype == '@struct' or doctype == '@union': + types.append(process_struct(infile)) + elif doctype == '@enum': + enums.append(process_enum(infile)) + elif doctype == '@macro': + macros.append(process_macro(infile)) + elif doctype == '@macrosection': + macros.append(process_macrosection(infile)) + elif doctype == '@typedef': + types.append(process_typedef(infile)) return macros, enums, types, functions - alldocs = [('Macros', macros), - ('Enums', enums), - ('Types (structs, unions and typedefs)', types), - ('Functions', functions)] - def output( - indexfile, macrosfile, enumsfile, typesfile, funcsdir, + title, indexfile, macrosfile, enumsfile, typesfile, funcsdir, macros, enums, types, functions): indexfile.write(''' -API Reference -============= +{title} +{titledecoration} .. toctree:: :maxdepth: 1 - macros - enums - types -''') + {macros} + {enums} + {types} +'''.format( + title=title, titledecoration='='*len(title), + macros=os.path.splitext(os.path.basename(macrosfile.name))[0], + enums=os.path.splitext(os.path.basename(enumsfile.name))[0], + types=os.path.splitext(os.path.basename(typesfile.name))[0], +)) for doc in functions: indexfile.write(' {}\n'.format(doc.funcname)) @@ -153,9 +200,10 @@ Types (structs, unions and typedefs) Synopsis -------- -*#include * +*#include * -'''.format(funcname=doc.funcname, secul='='*len(doc.funcname))) +'''.format(funcname=doc.funcname, secul='='*len(doc.funcname), + filename=doc.filename)) doc.write(f) def process_macro(infile): @@ -164,6 +212,17 @@ def process_macro(infile): macro_name = line.split()[1] return MacroDoc(macro_name, content) +def process_macrosection(infile): + content = read_content(infile) + return MacroSectionDoc(content) + +def process_typedef(infile): + content = read_content(infile) + typedef = infile.readline() + typedef = re.sub(r';\n$', '', typedef) + typedef = re.sub(r'typedef ', '', typedef) + return TypedefDoc(typedef, content) + def process_enum(infile): members = [] enum_name = None @@ -176,7 +235,7 @@ def process_enum(infile): member_content = read_content(infile) line = infile.readline() items = line.split() - member_name = items[0] + member_name = items[0].rstrip(',') if len(items) >= 3: member_content.insert(0, '(``{}``) '\ .format(' '.join(items[2:]).rstrip(','))) @@ -185,7 +244,7 @@ def process_enum(infile): enum_name = line.rstrip().split()[1] enum_name = re.sub(r';$', '', enum_name) break - return StructDoc(enum_name, content, members, 'macro') + return EnumDoc(enum_name, content, members) def process_struct(infile): members = [] @@ -226,7 +285,9 @@ def process_function(domain, infile): func_proto = re.sub(r';\n$', '', func_proto) func_proto = re.sub(r'\s+', ' ', func_proto) func_proto = re.sub(r'NGHTTP2_EXTERN ', '', func_proto) - return FunctionDoc(func_proto, content, domain) + func_proto = re.sub(r'typedef ', '', func_proto) + filename = os.path.basename(infile.name) + return FunctionDoc(func_proto, content, domain, filename) def read_content(infile): content = [] @@ -251,6 +312,8 @@ def transform_content(content): if __name__ == '__main__': parser = argparse.ArgumentParser(description="Generate API reference") + parser.add_argument('--title', default='API Reference', + help='title of index page') parser.add_argument('index', type=argparse.FileType('w'), help='index output file') parser.add_argument('macros', type=argparse.FileType('w'), @@ -269,12 +332,13 @@ if __name__ == '__main__': types = [] funcs = [] for infile in args.files: - m, e, t, f = make_api_ref(args.files) + m, e, t, f = make_api_ref(infile) macros.extend(m) enums.extend(e) types.extend(t) funcs.extend(f) funcs.sort(key=lambda x: x.funcname) output( + args.title, args.index, args.macros, args.enums, args.types, args.funcsdir, macros, enums, types, funcs)