From ee484b77f9587b0bef6c8b59b313dbe5484bb7a5 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 4 Nov 2018 12:31:22 +0100 Subject: [PATCH] m.dox: support adding custom classes to the links. --- doc/plugins/links.rst | 21 ++++++- pelican-plugins/m/dox.py | 47 ++++++++++------ .../m/test/dox/page_css_classes.html | 55 +++++++++++++++++++ pelican-plugins/m/test/test_dox.py | 9 +++ 4 files changed, 111 insertions(+), 21 deletions(-) create mode 100644 pelican-plugins/m/test/dox/page_css_classes.html diff --git a/doc/plugins/links.rst b/doc/plugins/links.rst index 3f124408..77de9354 100644 --- a/doc/plugins/links.rst +++ b/doc/plugins/links.rst @@ -236,14 +236,15 @@ Download the `m/dox.py <{filename}/plugins.rst>`_ file, put it including the ``m/`` directory into one of your :py:`PLUGIN_PATHS` and add :py:`m.dox` package to your plugins in ``pelicanconf.py``. The plugin uses Doxygen tag files to get a list of linkable symbols and you need to provide -list of 3-tuples containing tag file path, URL prefix and list of implicitly -prepended namespaces in :py:`M_DOX_TAGFILES` configuration to make the plugin -work. Example configuration: +list of tuples containing tag file path, URL prefix and an optional list of +implicitly prepended namespaces in :py:`M_DOX_TAGFILES` configuration to make +the plugin work. Example configuration: .. code:: python PLUGINS += ['m.dox'] M_DOX_TAGFILES = [ + ('doxygen/stl.tag', 'https://en.cppreference.com/w/'), ('doxygen/corrade.tag', 'https://doc.magnum.graphics/corrade/', ['Corrade::']), ('doxygen/magnum.tag', 'https://doc.magnum.graphics/magnum/', ['Magnum::'])] @@ -293,6 +294,20 @@ and adding the :rst:`:class:` option. - :dox:`Link to an anchor ` - Flat link: :dox-flat:`plugin-management` +It's also possible to add custom CSS classes via a fourth tuple item. For +example, to make the links consistent with the Doxygen theme (where +documentation links are not underscored, internal doxygen links are bold and +external not), you could do this: + +.. code:: python + + PLUGINS += ['m.dox'] + M_DOX_TAGFILES = [ + ('doxygen/stl.tag', 'https://en.cppreference.com/w/', [], + ['m-flat']), + ('doxygen/your-lib.tag', 'https://doc.your-lib.com/', ['YourLib::'], + ['m-flat', 'm-text', 'm-strong'])] + .. note-success:: If you haven't noticed yet, m.css also provides a diff --git a/pelican-plugins/m/dox.py b/pelican-plugins/m/dox.py index 00427d54..7d74208d 100644 --- a/pelican-plugins/m/dox.py +++ b/pelican-plugins/m/dox.py @@ -61,8 +61,12 @@ def init(pelicanobj): symbol_mapping = {} symbol_prefixes = [''] - for tagfile, path, prefixes in tagfiles: - tagfile_basenames += [(os.path.splitext(os.path.basename(tagfile))[0], path)] + for f in tagfiles: + tagfile, path = f[:2] + prefixes = f[2] if len(f) > 2 else [] + css_classes = f[3] if len(f) > 3 else [] + + tagfile_basenames += [(os.path.splitext(os.path.basename(tagfile))[0], path, css_classes)] symbol_prefixes += prefixes tree = ET.parse(tagfile) @@ -72,68 +76,73 @@ def init(pelicanobj): # Linking to pages if child.attrib['kind'] == 'page': link = path + child.find('filename').text + '.html' - symbol_mapping[child.find('name').text] = (child.find('title').text, link) + symbol_mapping[child.find('name').text] = (child.find('title').text, link, css_classes) # Linking to files if child.attrib['kind'] == 'file': link = path + child.find('filename').text + ".html" - symbol_mapping[child.find('path').text + child.find('name').text] = (None, link) + symbol_mapping[child.find('path').text + child.find('name').text] = (None, link, css_classes) for member in child.findall('member'): if not 'kind' in member.attrib: continue # Preprocessor defines and macros if member.attrib['kind'] == 'define': - symbol_mapping[member.find('name').text + ('()' if member.find('arglist').text else '')] = (None, link + '#' + member.find('anchor').text) + symbol_mapping[member.find('name').text + ('()' if member.find('arglist').text else '')] = (None, link + '#' + member.find('anchor').text, css_classes) # Linking to namespaces, structs and classes if child.attrib['kind'] in ['class', 'struct', 'namespace']: name = child.find('name').text link = path + child.findtext('filename') # can be empty (cppreference tag file) - symbol_mapping[name] = (None, link) + symbol_mapping[name] = (None, link, css_classes) for member in child.findall('member'): if not 'kind' in member.attrib: continue # Typedefs, constants if member.attrib['kind'] == 'typedef' or member.attrib['kind'] == 'enumvalue': - symbol_mapping[name + '::' + member.find('name').text] = (None, link + '#' + member.find('anchor').text) + symbol_mapping[name + '::' + member.find('name').text] = (None, link + '#' + member.find('anchor').text, css_classes) # Functions if member.attrib['kind'] == 'function': # can be empty (cppreference tag file) - symbol_mapping[name + '::' + member.find('name').text + "()"] = (None, link + '#' + member.findtext('anchor')) + symbol_mapping[name + '::' + member.find('name').text + "()"] = (None, link + '#' + member.findtext('anchor'), css_classes) # Enums with values if member.attrib['kind'] == 'enumeration': enumeration = name + '::' + member.find('name').text - symbol_mapping[enumeration] = (None, link + '#' + member.find('anchor').text) + symbol_mapping[enumeration] = (None, link + '#' + member.find('anchor').text, css_classes) for value in member.findall('enumvalue'): - symbol_mapping[enumeration + '::' + value.text] = (None, link + '#' + value.attrib['anchor']) + symbol_mapping[enumeration + '::' + value.text] = (None, link + '#' + value.attrib['anchor'], css_classes) # Sections for section in child.findall('docanchor'): - symbol_mapping[section.text] = (section.attrib.get('title', ''), link + '#' + section.text) + symbol_mapping[section.text] = (section.attrib.get('title', ''), link + '#' + section.text, css_classes) def dox(name, rawtext, text, lineno, inliner: Inliner, options={}, content=[]): title, target, hash = parse_link(text) - set_classes(options) + # Otherwise adding classes to the options behaves globally (uh?) + _options = dict(options) + set_classes(_options) + # Avoid assert on adding to undefined member later + if 'classes' not in _options: _options['classes'] = [] # Try linking to the whole docs first - for basename, url in tagfile_basenames: + for basename, url, css_classes in tagfile_basenames: if basename == target: if not title: # TODO: extract title from index page in the tagfile logger.warning("Link to main page `{}` requires a title".format(target)) title = target - node = nodes.reference(rawtext, title, refuri=url + hash, **options) + _options['classes'] += css_classes + node = nodes.reference(rawtext, title, refuri=url + hash, **_options) return [node], [] for prefix in symbol_prefixes: if prefix + target in symbol_mapping: - link_title, url = symbol_mapping[prefix + target] + link_title, url, css_classes = symbol_mapping[prefix + target] if title: use_title = title elif link_title: @@ -143,7 +152,9 @@ def dox(name, rawtext, text, lineno, inliner: Inliner, options={}, content=[]): logger.warning("Doxygen anchor `{}` has no title, using its ID as link title".format(target)) use_title = target - node = nodes.reference(rawtext, use_title, refuri=url + hash, **options) + + _options['classes'] += css_classes + node = nodes.reference(rawtext, use_title, refuri=url + hash, **_options) return [node], [] # TODO: print file and line @@ -152,10 +163,10 @@ def dox(name, rawtext, text, lineno, inliner: Inliner, options={}, content=[]): #prb = inliner.problematic(rawtext, rawtext, msg) if title: logger.warning("Doxygen symbol `{}` not found, rendering just link title".format(target)) - node = nodes.inline(rawtext, title, **options) + node = nodes.inline(rawtext, title, **_options) else: logger.warning("Doxygen symbol `{}` not found, rendering as monospace".format(target)) - node = nodes.literal(rawtext, target, **options) + node = nodes.literal(rawtext, target, **_options) return [node], [] def register(): diff --git a/pelican-plugins/m/test/dox/page_css_classes.html b/pelican-plugins/m/test/dox/page_css_classes.html new file mode 100644 index 00000000..f6aa3de3 --- /dev/null +++ b/pelican-plugins/m/test/dox/page_css_classes.html @@ -0,0 +1,55 @@ + + + + + m.dox | A Pelican Blog + + + + + + +
+
+
+
+
+
+

m.dox

+ + +

These should produce warnings:

+
    +
  • Link to nonexistent name will be rendered as code: nonExistent()
  • +
  • Link to nonexistent name with custom title will be just text
  • +
  • Link to a section that doesn't have a title will keep the ID (this may +break on tagfile update, watch out): corrade-cmake-add-test
  • +
  • Link to index page without title will have the tag file basename: +corrade
  • +
+ +
+
+
+
+
+ + diff --git a/pelican-plugins/m/test/test_dox.py b/pelican-plugins/m/test/test_dox.py index b6c7d56e..5820abaa 100644 --- a/pelican-plugins/m/test/test_dox.py +++ b/pelican-plugins/m/test/test_dox.py @@ -36,3 +36,12 @@ class Dox(PluginTestCase): }) self.assertEqual(*self.actual_expected_contents('page.html')) + + def test_css_classes(self): + self.run_pelican({ + 'PLUGINS': ['m.htmlsanity', 'm.dox'], + 'M_DOX_TAGFILES': [ + ('../doc/doxygen/corrade.tag', 'https://doc.magnum.graphics/corrade/', ['Corrade::'], ['m-flat', 'm-text', 'm-strong'])] + }) + + self.assertEqual(*self.actual_expected_contents('page.html', 'page_css_classes.html')) -- 2.30.2