Moving librsvg's documentation to gi-docgen

Translations: es - Tags: documentation, gnome, librsvg

Librsvg's documentation tooling is pretty ancient. The man page for rsvg-convert is written by hand in troff, and the C library's reference documentation still uses the venerable gtk-doc.

As part of the modernization effort, I have turned the man page into a reStructuredText document, and the C API documentation into gi-docgen. This post describes how I did that.

You can read librsvg's new documentation here.

From man to rst

The man page for rsvg-convert was written in troff, which is pretty cumbersome. The following gunk defines a little paragraph and a table:

You can also specify dimensions as CSS lengths, for example
.B 10px
or \"
.BR 8.5in .
The unit specifiers supported are as follows:
tab (@);
l lx.
pixels (the unit specifier can be omitted)
points, 1/72 inch
picas, 1/6 inch

Yeah, nope. We have better tools now like rst2man, which take a reStructuredText document — fancy plain text — and turn it into a troff man page. I just had to use a command line like

pandoc --from=man --to=rst rsvg-convert.1 > rsvg-convert.rst

and then tweak the output a little:

You can also specify dimensions as CSS lengths, for example ``10px`` or
``8.5in``. The unit specifiers supported are as follows:

   == ==========================================
   px pixels (the unit specifier can be omitted)
   in inches
   cm centimeters
   mm millimeters
   pt points, 1/72 inch
   pc picas, 1/6 inch
   == ==========================================

Much better, right?

I've learned that Pandoc is awesome. Pure magic, highly recommended.

I hope to integrate the man page into a prettier user manual for rsvg-convert at some point. It's no longer a trivial program, and its options allow for some interesting combinations that could use some illustrations and generally more detail than a man page.

From gtk-doc to gi-docgen

I highly recommend that you read Emmanuele's initial description of gi-docgen, which includes the history of gtk-doc, a description of its shortcomings, and how gi-docgen is a simpler tool that leverages the fact that GObject Introspection already slurps documentation from source code and so obviates most of gtk-doc already.

Summary of how gi-docgen works:

  • The C code has documentation comments in Markdown format, with annotations for GObject Introspection. (Note: librsvg has no C code for the library, so those documentation comments actually live in the .h header files that it installs for the benefit of C programs.)

  • The library gets compiled and introspected. In this step, g-ir-scanner(1) extracts annotations and documentation from the source code and puts them in the MyLibrary.gir XML file.

  • You write a small configuration file to tell gi-docgen about the structure of your documentation. Unlike gtk-doc, you don't need to write a DocBook skeleton or anything complicated. Stand-alone chapters can be individual Markdown files, and the configuration file just lists them in the order you want them to appear. Gi-docgen automatically includes all the classes, types, functions, etc. from your code into the docs.

  • ... it runs very fast. Gtk-doc was always slow due to xsltproc and complicated stylesheets to turn a DocBook document into browsable HTML documentation. Gi-docgen is much leaner.

Doing the conversion

Unlike the mostly automatic pandoc step for the man page, I converted the documentation comments to from DocBook to Markdown by hand. For librsvg this took me a moderately caffeinated afternoon; it's a little fiddly business, but nothing out of this world.

You can look forward to having good error messages from gi-docgen when something goes wrong, unlike gtk-doc, whose errors I always tended to ignore until the last minute because they were so hard to discern and diagnose.

Some hints:

  • DocBook hyperlinks that looked like <ulink url="blahblah.html">blah blah</ulink> get turned into [blah blah](blahblah.html) Markdown.

  • Gi-docgen allows references to methods like [method@Gtk.Button.set_child] - see the linking documentation for other kinds of links.

  • You can get progressively fancy with introspection attributes.

  • There is no direct mapping between DocBook's extremely granular semantic markup and Markdown conventions, so for example I'd substitute both <literal>foobar</literal> and <filename>/foo/bar</filename> for `foobar` and `/foo/bar`, respectively (i.e. the text I wanted to show, between backticks, to indicate verbatim text).

Librsvg seemed to include verbatim text blocks in gtk-doc delimited like this:

 * blah_blah():
 * For example:
 * |[
 * verbatim text goes here
 * ]|
 * Etc. etc.

Those can go between ``` triple backticks in Markdown:

 * blah_blah():
 * For example:
 * ```
 * verbatim text goes here
 * ```
 * Etc. etc.

Errors I found

My first manual run of gi-docgen looked like this:

$ gi-docgen check Rsvg-2.0.gir 
INFO: Loading config file: None
INFO: Search paths: ['/home/federico/src/librsvg/gi-docgen/_build', '/home/federico/.local/share/gir-1.0', '/home/federico/.local/share/flatpak/exports/share/gir-1.0', '/var/lib/flatpak/exports/share/gir-1.0', '/usr/local/share/gir-1.0', '/usr/share/gir-1.0']
INFO: Elapsed time 1.601 seconds
WARNING: Symbol 'Rsvg.HandleFlags' at <unknown>:0 is not documented
WARNING: Return value for symbol 'Rsvg.Handle.get_dimensions_sub' is not documented
WARNING: Return value for symbol 'Rsvg.Handle.get_geometry_for_element' is not documented
WARNING: Return value for symbol 'Rsvg.Handle.get_geometry_for_layer' is not documented
WARNING: Return value for symbol 'Rsvg.Handle.get_position_sub' is not documented
WARNING: Return value for symbol 'Rsvg.Handle.render_document' is not documented
WARNING: Return value for symbol 'Rsvg.Handle.render_element' is not documented
WARNING: Return value for symbol 'Rsvg.Handle.render_layer' is not documented
WARNING: Return value for symbol 'Rsvg.Handle.set_stylesheet' is not documented
WARNING: Symbol 'Rsvg.Handle.base-uri' at <unknown>:0 is not documented
WARNING: Symbol 'Rsvg.Handle.dpi-x' at <unknown>:0 is not documented
WARNING: Symbol 'Rsvg.Handle.dpi-y' at <unknown>:0 is not documented
WARNING: Symbol 'Rsvg.cleanup' at include/librsvg/rsvg.h:447 is not documented
WARNING: Symbol 'Rsvg.DEPRECATED_FOR' at include/librsvg/rsvg.h:47 is not documented
WARNING: Parameter 'f' of symbol 'Rsvg.DEPRECATED_FOR' is not documented

The warnings like WARNING: Return value ... is not documented are easy to fix; the comment blocks had their descriptions, but they were missing the Returns: part.

The warnings like WARNING: Symbol 'Rsvg.Handle.base-uri' at <unknown>:0 is not documented are different. Those are GObject properties, which previously were documented like this:

 * RsvgHandle::base-uri:
 * Base URI, to be used to resolve relative references for resources.  See the section
 * "Security and locations of referenced files" for details.

There is a syntax error there! The symbol line should use a single colon between the class name and the property name, e.g. RsvgHandle:base-uri instead of RsvgHandle::base-uri. This one, plus the other properties that showed up as not documented, had the same kind of typo.

The first warning, WARNING: Symbol 'Rsvg.HandleFlags' at <unknown>:0 is not documented, turned out to be that there were two documentation comments with the same title for RsvgHandleFlags, and the second one was empty — and the last one wins. I left a single one with the actual docs.

Writing standalone chapters

Librsvg had a few chapters like doc/foo.xml, doc/bar.xml that were included in the reference documentation; those were a DocBook <chapter> each. I was able to convert them to Markdown with pandoc individually, and then add a Title: heading in the first line of each .md file — that's what gi-docgen uses to build the table of contents in the documentation's starting page.

Title: Overview of Librsvg

# Overview of Librsvg

Librsvg is a library for rendering Scalable Vector Graphics files (SVG).
Blah blah blah blah.

Build scripts

There are plenty of examples for using gi-docgen with meson; you can look at how it is done in gtk.

However, librsvg is still using Autotools! You can steal the following bits:

Publishing the documentation

Gtk-doc assumed that magic happened somewhere in to generate the documentation and publish it. Gi-docgen assumes that your project publishes it with Gitlab pages.

Indeed, the new documentation is published there — you can see how it is generated in .gitlab-ci.yml. Note that there are two jobs: the reference job generates gi-docgen's HTML in a public/Rsvg-2.0 directory, and the pages job integrates it with the Rust API documentation and publishes both together.

Linking the docs to the main developer's site

Finally, librsvg's docs are linked from the GNOME Platform Introduction. I submitted a merge request to the developer-www project to update it.

That's all! I hope this is useful for someone who wants to move from gtk-doc to gi-docgen, which is a much more pleasant tool!