Commits

Matt Williams  committed 6530831

Initial commit of doxylink extension.

Doxylink is a Sphinx extension to allow linking to Doxygen generated HTML documentation from within Sphinx by parsing the Doxygen tag file.

  • Participants
  • Parent commits 038d5b3

Comments (0)

Files changed (7)

 
 pyqt4:
    Sebastian Wiesner <lunaryorn@googlemail.com>
+
+doxylink
+   Matt Williams <matt@milliams.com>
 - issuetracker: link to different issue trackers
 - epydoc: cross-reference eypdoc generated documentation
 - pyqt4: markup for PyQt4 signals
+- doxylink: Link to external Doxygen-generated HTML documentation
 
 .. _aafigure: http://docutils.sourceforge.net/sandbox/aafigure/
 

File doxylink/MANIFEST.in

+include README
+include LICENSE
+include CHANGES.*

File doxylink/setup.cfg

+[egg_info]
+tag_build = dev
+tag_date = true
+
+[aliases]
+release = egg_info -RDb ''

File doxylink/setup.py

+# -*- coding: utf-8 -*-
+
+from setuptools import setup, find_packages
+
+long_desc = '''
+This package contains the doxylink Sphinx extension.
+
+.. add description here ..
+'''
+
+requires = ['Sphinx>=0.6']
+
+setup(
+    name='doxylink',
+    version='0.1',
+    url='http://bitbucket.org/birkenfeld/sphinx-contrib',
+    download_url='http://pypi.python.org/pypi/doxylink',
+    license='BSD',
+    author='Matt Williams',
+    author_email='matt@milliams.com',
+    description='Sphinx extension doxylink',
+    long_description=long_desc,
+    zip_safe=False,
+    classifiers=[
+        'Development Status :: 4 - Beta',
+        'Environment :: Console',
+        'Environment :: Web Environment',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: BSD License',
+        'Operating System :: OS Independent',
+        'Programming Language :: Python',
+        'Topic :: Documentation',
+        'Topic :: Utilities',
+    ],
+    platforms='any',
+    packages=find_packages(),
+    include_package_data=True,
+    install_requires=requires,
+    namespace_packages=['sphinxcontrib'],
+)

File doxylink/sphinxcontrib/__init__.py

+# -*- coding: utf-8 -*-
+"""
+    sphinxcontrib
+    ~~~~~~~~~~~~~
+
+    This package is a namespace package that contains all extensions
+    distributed in the ``sphinx-contrib`` distribution.
+
+    :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+
+__import__('pkg_resources').declare_namespace(__name__)
+

File doxylink/sphinxcontrib/doxylink.py

+# -*- coding: utf-8 -*-
+"""
+doxylink
+~~~~~~~~
+
+Sphinx extension to link to external Doxygen API documentation.
+
+It works much like the extlinks extension but it does some more processing to link C++ symbols against their Doxygen HTML documentation.
+
+.. confval:: doxylink
+
+	The environment is set up with a dictionary mapping the interpereted text role
+	to a tuple of tag file and prefix:
+
+	.. code-block:: python
+
+		doxylink = {
+			'polyvox' : ('/home/matt/PolyVox.tag', '/home/matt/PolyVox/html/'),
+			'qtogre' : ('/home/matt/QtOgre.tag', '/home/matt/QtOgre/html/'),
+		}
+
+This allows one to do:
+
+.. code-block:: rst
+
+	:polyvox:`Array <PolyVox::Array>`.
+	:polyvox:`PolyVox::Volume`
+	:qtogre:`QtOgre::Log`
+	:polyvox:`tidyUpMemeory(int) <tidyUpMemory>`
+	:polyvox:`PolyVox::Array::operator[]`
+
+:requires: Python 2.5
+
+.. todo::
+	
+	Make the extension atuomatically re-run if the tag file is altered on disc
+	
+	Find a way to parse the tag file to a DOM tree *once* and then just reference it from then on.
+
+:copyright: Copyright 2010 by Matt Williams
+:license: BSD, see LICENSE for details.
+"""
+
+from docutils import nodes, utils
+
+from sphinx.util.nodes import split_explicit_title
+
+import xml.etree.ElementTree as ET
+
+def find_url(doc, symbol):
+	"""
+	Return the URL for a given symbol.
+	
+	This is where the magic happens.
+	This function could be a lot more clever. At present it required the passed symbol to be almost exactly the same as the entries in the Doxygen tag file.
+	
+	.. todo::
+		
+		Maybe print a list of all possible matches as a warning (but still only return the first)
+	
+	:Parameters:
+		doc : xml.etree.ElementTree
+			The XML DOM object
+		symbol : string
+			The symbol to lookup in the file. E.g. something like 'PolyVox::Array' or 'tidyUpMemory'
+	
+	:return: String representing the filename part of the URL
+	"""
+	
+	#First check for an exact match with a top-level object (namespaces, objects etc.)
+	
+	#env = inliner.document.settings.env
+	
+	matches = []
+	for compound in doc.findall('.//compound'):
+		if compound.find('name').text == symbol:
+			matches += [compound.find('filename').text]
+	
+	if len(matches) > 1:
+		pass
+		#env.warn(env.docname, 'There were multiple matches for `%s`: %s' % (symbol, matches))
+	if len(matches) == 1:
+		return matches[0]
+	
+	
+	#Strip off first namespace bit of the compound name so that 'ArraySizes' can match 'PolyVox::ArraySizes'
+	for compound in doc.findall('.//compound'):
+		symbol_list = compound.find('name').text.split('::', 1)
+		if len(symbol_list) == 2:
+			reducedsymbol = symbol_list[1]
+			if reducedsymbol == symbol:
+				return compound.find('filename').text
+	
+	#Now split the symbol by '::'. Find an exact match for the first part and then a member match for the second
+	#So PolyVox::Array::operator[] becomes like {namespace: "PolyVox::Array", endsymbol: "operator[]"}
+	symbol_list = symbol.rsplit('::', 1)
+	if len(symbol_list) == 2:
+		namespace = symbol_list[0]
+		endsymbol = symbol_list[1]
+		for compound in doc.findall('.//compound'):
+			if compound.find('name').text == namespace:
+				for member in compound.findall('member'):
+#					#If this compound object contains the matching member then return it
+					if member.find('name').text == endsymbol:
+						return member.find('anchorfile').text + '#' + member.find('anchor').text
+	
+	#Then we'll look at unqualified members
+	for member in doc.findall('.//member'):
+		if member.find('name').text == symbol:
+			return member.find('anchorfile').text + '#' + member.find('anchor').text
+	
+	return None
+
+def create_role(app, tag_filename, rootdir):
+	def find_doxygen_link(name, rawtext, text, lineno, inliner, options={}, content=[]):
+		text = utils.unescape(text)
+		# from :name:`title <part>`
+		has_explicit_title, title, part = split_explicit_title(text)
+		
+		try:
+			tag_file = ET.parse(tag_filename)
+		except (IOError):
+			env = inliner.document.settings.env
+			env.warn(env.docname, 'Could not open %s' % tag_filename)
+		else:
+			url = find_url(tag_file, part)
+			if url:
+				full_url = rootdir + url
+				pnode = nodes.reference(title, title, internal=False, refuri=full_url)
+				return [pnode], []
+			#By here, no match was found
+			env = app.env
+			env.warn(env.docname, 'Could not find match for `%s` in `%s` tag file' % (part, tag_filename), lineno)
+			
+		full_url="#"
+		#TODO find which command to use to just output it as plain text (no link) in this case
+		pnode = nodes.reference(title, title, internal=False, refuri=full_url)
+		return [pnode], []
+		
+	return find_doxygen_link
+
+def setup_doxylink_roles(app):
+	for name, [tag_filename, rootdir] in app.config.doxylink.iteritems():
+		app.add_role(name, create_role(app, tag_filename, rootdir))
+
+def setup(app):
+	app.add_config_value('doxylink', {}, 'env')
+	app.connect('builder-inited', setup_doxylink_roles)