Skip to content

Commit

Permalink
sphinx-doc-v3-compat: split cdomain into v2 and v3
Browse files Browse the repository at this point in the history
- 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 <markus.heiser@darmarit.de>
  • Loading branch information
return42 committed Aug 13, 2020
1 parent fad45af commit 70673dc
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 151 deletions.
1 change: 0 additions & 1 deletion .gitignore
@@ -1,7 +1,6 @@
*~
gh-pages
local/
docs/linuxdoc-api

# Byte-compiled / optimized / DLL files
__pycache__/
Expand Down
1 change: 1 addition & 0 deletions docs/.gitignore
@@ -0,0 +1 @@
linuxdoc-api/
157 changes: 7 additions & 150 deletions linuxdoc/cdomain.py
Expand Up @@ -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 <linuxdoc.cdomain.CObject>` directives."
145 changes: 145 additions & 0 deletions 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 <linuxdoc.cdomain.CObject>` directives."
29 changes: 29 additions & 0 deletions 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.
"""

0 comments on commit 70673dc

Please sign in to comment.