Chapter 26. Program listings

Table of Contents

Fitting text
Reducing font size
Breaking long lines
External code files
Missing text
Using XInclude for text inclusions
Annotating program listings
Line annotations
Line numbering
Callouts
Callouts on imported text
Callouts on graphics
Syntax highlighting

Technical documentation often requires presentation of examples of program code. The examples must preserve the line breaks and indents in order to be understood. The preferred element to contain such examples is programlisting, although screen or literallayout may also be used. If you use literallayout, you should set its class attribute to the value of monospaced to ensure presentation in a monospaced font by the stylesheets. The programlisting and screen elements are always presented in a monospaced font. Any of these elements can also be wrapped in example or figure elements if you want to add a title. This chapter focuses on programlisting, but most of the features apply to the other display elements as well.

You can type your text directly in a programlisting element, and its indents and line breaks will be preserved. Use multiple spaces instead of tab characters for indents. Tab characters are not defined in the XSL-FO spec, so they will likely be converted to single spaces and ruin your indent alignments.

A programlisting element permits some child elements that you can use to highlight certain text, including replaceable, emphasis, and parameter among others. You can also use character entities such as &trade; or math symbols. In fact, you must use character entities &lt;, &gt;, and &amp; for the XML special characters <, >, and &, which would otherwise be interpreted as XML markup. Keep in mind that element tags and entities take up more space in the raw XML than in the output, so you have to take that into account while editing for alignment.

You can turn off interpretation of characters that would be recognized as XML markup by enclosing the text in a CDATA section, as in the following example:

Example 26.1. CDATA example

<programlisting><![CDATA[                     Start of CDATA section
# Shell redirection and background processing
sort -o sorted  < unsorted  &
]]>                                           End of CDATA section
</programlisting>

Without the CDATA markup, the < and & characters would be interpreted as start-of-element and start-of-entity characters, respectively. Within the CDATA markup, they are treated as ordinary characters. In fact, the only markup recognized within CDATA is the sequence ]]> to terminate the CDATA section. That means you cannot use DocBook elements like <emphasis> or entities like &trade; within a CDATA section.

Fitting text

Some code examples may have lines that are too long or too deeply indented to fit on a printed page. Long lines are not a problem in HTML output, because a browser window can be scrolled to view long lines. But printed text should not exceed the established margins. Two possible solutions are reducing the font size or breaking long lines.

Reducing font size

One solution is to reduce the font size for such listings. You can set the font size for all listings by adding a font-size attribute to the monospace.verbatim.properties attribute-set.

But you may only want to reduce the font size for certain programlisting elements that have this problem. If so, you can use a combination of a processing instruction and a conditional attribute value. The processing instruction could look like this:

<programlisting><?db-font-size 75% ?># A long line listing
  ...

The name of the PI is your choice. Then make the attribute value conditional on this PI by adding the following to your print customization layer:

<xsl:attribute-set name="monospace.verbatim.properties">
  <xsl:attribute name="font-size">
    <xsl:choose>
      <xsl:when test="processing-instruction('db-font-size')"><xsl:value-of
           select="processing-instruction('db-font-size')"/></xsl:when>
      <xsl:otherwise>inherit</xsl:otherwise>
    </xsl:choose>
  </xsl:attribute>
</xsl:attribute-set>

The xsl:attribute element will be evaluated for each programlisting. If it contains a PI with matching name, it takes its value to be the font-size. The value can be a percentage as in this example, or a fixed value such as 7pt. Be sure to include the xsl:otherwise clause to avoid generating an empty attribute value.

Reducing font size will work when the lines are close to fitting. But when lines are very long, you would have to reduce the font size so much that the text becomes hard to read. Those lines require some means of breaking the lines.

Breaking long lines

Another solution for fitting text in a programlisting is to break each long line into two lines. The best results will be had from manually breaking any long lines after you see which ones don't fit on a page. Manual line breaking permits you to match the appropriate indent level of the text, or break at appropriate points in the syntax. But this manual solution may not be practical for documents with many listings.

You can create automatic line breaks by permitting the lines to wrap inside the program listing. You can do that by setting the wrap-option attribute in the monospace.verbatim.properties attribute-set:

<xsl:attribute-set name="monospace.verbatim.properties">
    <xsl:attribute name="wrap-option">wrap</xsl:attribute>
</xsl:attribute-set>

This will break a long line on a space between words, but it leaves no indication that the first line should logically be continued with the second line. It would be better if the line break inserted a character at the end of the first line that indicated the line break. Beginning with version 1.67 of the stylesheets, you can do that by setting the hyphenate.verbatim parameter to 1. You also need to add another attribute to the attribute set:

<xsl:attribute-set name="monospace.verbatim.properties">
    <xsl:attribute name="wrap-option">wrap</xsl:attribute>
    <xsl:attribute name="hyphenation-character">\</xsl:attribute>
</xsl:attribute-set>

The second attribute hyphenation-character identifies the character to use when the line is broken, in this case a backslash. You could use any Unicode character you like, but the character has to be available to the XSL-FO processor at that point.