From 70673dcf69e705e08d81f53794895dc15c4920b3 Mon Sep 17 00:00:00 2001 From: Markus Heiser Date: Thu, 13 Aug 2020 17:48:51 +0200 Subject: [PATCH] sphinx-doc-v3-compat: split cdomain into v2 and v3 - cdomainv2 (Sphinx v<3.0) - cdomainv3 (Sphinx v>=3.0) Class 'CObject' and class 'CDomain' from 'cdomain3' are placeholder which can be used to implement a revise of the functions from 'cdomainv2'. Signed-off-by: Markus Heiser --- .gitignore | 1 - docs/.gitignore | 1 + linuxdoc/cdomain.py | 157 ++---------------------------------------- linuxdoc/cdomainv2.py | 145 ++++++++++++++++++++++++++++++++++++++ linuxdoc/cdomainv3.py | 29 ++++++++ 5 files changed, 182 insertions(+), 151 deletions(-) create mode 100644 docs/.gitignore create mode 100644 linuxdoc/cdomainv2.py create mode 100644 linuxdoc/cdomainv3.py diff --git a/.gitignore b/.gitignore index ede5c0c..aa87041 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ *~ gh-pages local/ -docs/linuxdoc-api # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..95b55b5 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +linuxdoc-api/ diff --git a/linuxdoc/cdomain.py b/linuxdoc/cdomain.py index c0f5070..f70e239 100644 --- a/linuxdoc/cdomain.py +++ b/linuxdoc/cdomain.py @@ -11,166 +11,23 @@ For user documentation see :ref:`customized-c-domain`. """ -import re - -from docutils import nodes -from docutils.parsers.rst import directives - import sphinx -from sphinx import addnodes -from sphinx.locale import _ -from sphinx.domains.c import CObject as Base_CObject -from sphinx.domains.c import CDomain as Base_CDomain - -# fixes https://github.com/sphinx-doc/sphinx/commit/0f49e30c51b5cc5055cda5b4b294c2dd9d1df573#r38750737 - -# pylint: disable=invalid-name -c_sig_re = re.compile( - r'''^([^(]*?) # return type - ([\w:.]+) \s* # thing name (colon allowed for C++) - (?: \((.*)\) )? # optionally arguments - (\s+const)? $ # const specifier - ''', re.VERBOSE) - -c_funcptr_sig_re = re.compile( - r'''^([^(]+?) # return type - (\( [^()]+ \)) \s* # name in parentheses - \( (.*) \) # arguments - (\s+const)? $ # const specifier - ''', re.VERBOSE) -# pylint: enable=invalid-name - -__version__ = '1.0.1' # Get Sphinx version major, minor, patch = sphinx.version_info[:3] # pylint: disable=invalid-name +if major >= 3: + from .cdomainv3 import CDomain + __version__ = 3 +else: + from .cdomainv2 import CDomain + __version__ = 2 + def setup(app): # pylint: disable=missing-docstring app.add_domain(CDomain, override=True) - return dict( version = __version__, parallel_read_safe = True, parallel_write_safe = True ) - -class CObject(Base_CObject): - - """ - Description of a C language object. - """ - option_spec = { - "name" : directives.unchanged - } - - is_function_like_macro = False - - def handle_func_like_macro(self, sig, signode): - u"""Handles signatures of function-like macros. - - If the objtype is 'function' and the the signature ``sig`` is a - function-like macro, the name of the macro is returned. Otherwise - ``False`` is returned. """ - - if not self.objtype == 'function': - return False - - m = c_funcptr_sig_re.match(sig) # pylint: disable=invalid-name - if m is None: - m = c_sig_re.match(sig) # pylint: disable=invalid-name - if m is None: - raise ValueError('no match') - - rettype, fullname, arglist, _const = m.groups() - arglist = arglist.strip() - if rettype or not arglist: - return False - - arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup - arglist = [a.strip() for a in arglist.split(",")] - - # has the first argument a type? - if len(arglist[0].split(" ")) > 1: - return False - - # This is a function-like macro, it's arguments are typeless! - signode += addnodes.desc_name(fullname, fullname) - paramlist = addnodes.desc_parameterlist() - signode += paramlist - - for argname in arglist: - param = addnodes.desc_parameter('', '', noemph=True) - # separate by non-breaking space in the output - param += nodes.emphasis(argname, argname) - paramlist += param - - self.is_function_like_macro = True - return fullname - - def handle_signature(self, sig, signode): - """Transform a C signature into RST nodes.""" - - fullname = self.handle_func_like_macro(sig, signode) - if not fullname: - fullname = super(CObject, self).handle_signature(sig, signode) - - if "name" in self.options: - if self.objtype == 'function': - fullname = self.options["name"] - else: - # FIXME: handle :name: value of other declaration types? - pass - return fullname - - def add_target_and_index(self, name, sig, signode): - # for C API items we add a prefix since names are usually not qualified - # by a module name and so easily clash with e.g. section titles - targetname = 'c.' + name - if targetname not in self.state.document.ids: - signode['names'].append(targetname) - signode['ids'].append(targetname) - signode['first'] = (not self.names) - self.state.document.note_explicit_target(signode) - inv = self.env.domaindata['c']['objects'] - if (name in inv and self.env.config.nitpicky): - if self.objtype == 'function': - if ('c:func', name) not in self.env.config.nitpick_ignore: - self.state_machine.reporter.warning( - 'duplicate C object description of %s, ' % name + - 'other instance in ' + self.env.doc2path(inv[name][0]), - line=self.lineno) - inv[name] = (self.env.docname, self.objtype) - - indextext = self.get_index_text(name) - if indextext: - if major == 1 and minor < 4: - # indexnode's tuple changed in 1.4 - # https://github.com/sphinx-doc/sphinx/commit/e6a5a3a92e938fcd75866b4227db9e0524d58f7c - self.indexnode['entries'].append( - ('single', indextext, targetname, '')) - else: - self.indexnode['entries'].append( - ('single', indextext, targetname, '', None)) - - def get_index_text(self, name): - if self.is_function_like_macro: # pylint: disable=no-else-return - return _('%s (C macro)') % name - else: - return super(CObject, self).get_index_text(name) - -class CDomain(Base_CDomain): - - """C language domain. - - """ - name = 'c' - label = 'C' - directives = { - 'function': CObject, - 'member': CObject, - 'macro': CObject, - 'type': CObject, - 'var': CObject, - } - "Use :py:class:`CObject ` directives." diff --git a/linuxdoc/cdomainv2.py b/linuxdoc/cdomainv2.py new file mode 100644 index 0000000..1e9fe8e --- /dev/null +++ b/linuxdoc/cdomainv2.py @@ -0,0 +1,145 @@ +# -*- coding: utf-8; mode: python -*- +u""" + cdomainv2 (Sphinx v<3.0) + ~~~~~~~~~~~~~~~~~~~~~~~~ + + Replacement for the sphinx c-domain. + + :copyright: Copyright (C) 2020 Markus Heiser + :license: GPL Version 2, June 1991 see Linux/COPYING for details. + + For user documentation see :ref:`customized-c-domain`. +""" + +from docutils import nodes +from docutils.parsers.rst import directives +import sphinx + +from sphinx import addnodes +from sphinx.locale import _ +from sphinx.domains.c import c_funcptr_sig_re, c_sig_re +from sphinx.domains.c import CObject as Base_CObject +from sphinx.domains.c import CDomain as Base_CDomain + +# Get Sphinx version +major, minor, patch = sphinx.version_info[:3] # pylint: disable=invalid-name + +class CObject(Base_CObject): + + """ + Description of a C language object. + """ + option_spec = { + "name" : directives.unchanged + } + + is_function_like_macro = False + + def handle_func_like_macro(self, sig, signode): + u"""Handles signatures of function-like macros. + + If the objtype is 'function' and the the signature ``sig`` is a + function-like macro, the name of the macro is returned. Otherwise + ``False`` is returned. """ + + if not self.objtype == 'function': + return False + + m = c_funcptr_sig_re.match(sig) # pylint: disable=invalid-name + if m is None: + m = c_sig_re.match(sig) # pylint: disable=invalid-name + if m is None: + raise ValueError('no match') + + rettype, fullname, arglist, _const = m.groups() + arglist = arglist.strip() + if rettype or not arglist: + return False + + arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup + arglist = [a.strip() for a in arglist.split(",")] + + # has the first argument a type? + if len(arglist[0].split(" ")) > 1: + return False + + # This is a function-like macro, it's arguments are typeless! + signode += addnodes.desc_name(fullname, fullname) + paramlist = addnodes.desc_parameterlist() + signode += paramlist + + for argname in arglist: + param = addnodes.desc_parameter('', '', noemph=True) + # separate by non-breaking space in the output + param += nodes.emphasis(argname, argname) + paramlist += param + + self.is_function_like_macro = True + return fullname + + def handle_signature(self, sig, signode): + """Transform a C signature into RST nodes.""" + + fullname = self.handle_func_like_macro(sig, signode) + if not fullname: + fullname = super(CObject, self).handle_signature(sig, signode) + + if "name" in self.options: + if self.objtype == 'function': + fullname = self.options["name"] + else: + # FIXME: handle :name: value of other declaration types? + pass + return fullname + + def add_target_and_index(self, name, sig, signode): + # for C API items we add a prefix since names are usually not qualified + # by a module name and so easily clash with e.g. section titles + targetname = 'c.' + name + if targetname not in self.state.document.ids: + signode['names'].append(targetname) + signode['ids'].append(targetname) + signode['first'] = (not self.names) + self.state.document.note_explicit_target(signode) + inv = self.env.domaindata['c']['objects'] + if (name in inv and self.env.config.nitpicky): + if self.objtype == 'function': + if ('c:func', name) not in self.env.config.nitpick_ignore: + self.state_machine.reporter.warning( + 'duplicate C object description of %s, ' % name + + 'other instance in ' + self.env.doc2path(inv[name][0]), + line=self.lineno) + inv[name] = (self.env.docname, self.objtype) + + indextext = self.get_index_text(name) + if indextext: + if major == 1 and minor < 4: + # indexnode's tuple changed in 1.4 + # https://github.com/sphinx-doc/sphinx/commit/e6a5a3a92e938fcd75866b4227db9e0524d58f7c + self.indexnode['entries'].append( + ('single', indextext, targetname, '')) + else: + self.indexnode['entries'].append( + ('single', indextext, targetname, '', None)) + + def get_index_text(self, name): + if self.is_function_like_macro: # pylint: disable=no-else-return + return _('%s (C macro)') % name + else: + return super(CObject, self).get_index_text(name) + +class CDomain(Base_CDomain): + + """C language domain. + + """ + name = 'c' + label = 'C' + directives = { + 'function': CObject, + 'member': CObject, + 'macro': CObject, + 'type': CObject, + 'var': CObject, + } + "Use :py:class:`CObject ` directives." diff --git a/linuxdoc/cdomainv3.py b/linuxdoc/cdomainv3.py new file mode 100644 index 0000000..3359192 --- /dev/null +++ b/linuxdoc/cdomainv3.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8; mode: python -*- +u""" + cdomainv3 (Sphinx v>=3.0) + ~~~~~~~~~~~~~~~~~~~~~~~~~ + + Replacement for the sphinx c-domain. + + :copyright: Copyright (C) 2020 Markus Heiser + :license: GPL Version 2, June 1991 see Linux/COPYING for details. + + For user documentation see :ref:`customized-c-domain`. +""" + +from sphinx.domains.c import CObject as Base_CObject +from sphinx.domains.c import CDomain as Base_CDomain + +# fixes https://github.com/sphinx-doc/sphinx/commit/0f49e30c51b5cc5055cda5b4b294c2dd9d1df573#r38750737 + +class CObject(Base_CObject): + + """ + Description of a C language object. + """ + +class CDomain(Base_CDomain): + + """C language domain. + + """