# Source Code Highlight Filter

The AsciiDoc distribution includes a source filter for highlighting code syntax.

## DocBook Outputs

AsciiDoc encloses the source code in a DocBook programlisting element and leaves source code highlighting to the DocBook toolchain (dblatex has a particularly nice programlisting highlighter). The DocBook programlisting element is assigned two attributes:

1. The language attribute is set to the AsciiDoc language attribute.

2. The linenumbering attribute is set to the AsciiDoc src_numbered attribute (numbered or unnumbered).

## HTML Outputs

You have the choice of three HTML source code highlighters, your selection is determined by the source-highlighter attribute (defaults to source-highlight):

Set the source-highlighter attribute from the `asciidoc(1)` command-line or in the document header (not in the document body, because the configuration file conditional macros are processed at load time).

### GNU Source Highlight

The default highlighter is the GNU source-highlight which can highlight html4, html5 and xhtml11 outputs. The GNU source-highlight must be installed and the source-highlight command must reside in the shell search PATH.

### Highlight

You can use Highlight syntax highlighter for xhtml11, html5 and html4 outputs (set the source-highlighter attribute to highlighter).

- The highlight command must reside in the shell search PATH.

- To make Highlighter your default highlighter put the following line your `~/.asciidoc/asciidoc.conf` file:

      source-highlighter=highlight

- The AsciiDoc encoding attribute is passed to Highlighter using the `--encoding` command-line option.

### Pygments

The Pygments syntax highlighter can be used for xhtml11 and html5 outputs (set the source-highlighter attribute to pygments).

- The pygmentize command must reside in the shell search PATH.

- You can customize Pygments CSS styles by editing `./stylesheets/pygments.css`. The `pygments.css` CSS file was generated with:

      from pygments.formatters import HtmlFormatter
      print HtmlFormatter().get_style_defs('.highlight')

- To make Pygments your default highlighter put the following line your `~/.asciidoc/asciidoc.conf` file:

      source-highlighter=pygments

- The AsciiDoc encoding attribute is passed to Pygments using the `-O` command-line option.

## Block attributes

The following attributes can be included in source code block attribute lists.

- style and language are mandatory.

- style, language and src_numbered are the first three positional attributes in that order.

- The args attribute allows the inclusion of arbitrary (highlighter dependent) command options.

style

  Set to source.

language

  The source code language name.

  The language names vary between highlighters — consult the selected highlighter manual.

src_numbered

  Set to numbered to include line numbers.

src_tab

  Set tab size (GNU source-highlight only).

args

  Include this attribute value in the highlighter command-line (HTML outputs) or in the `programlisting` element (DocBook).

## Testing

Test the filter by converting the test file to HTML with AsciiDoc:

    $ asciidoc -v ./filters/source/source-highlight-filter-test.txt
    $ firefox ./filters/source/source-highlight-filter-test.html &

## Examples

### Source code paragraphs

The `source` paragraph style will highlight a paragraph of source code. These three code paragraphs:

    [source,python]
    if n < 0: print 'Hello World!'

    :language: python

    [source]
    if n < 0: print 'Hello World!'

    [source,ruby,numbered]
    [true, false].cycle([0, 1, 2, 3, 4]) do |a, b|
        puts "#{a.inspect} => #{b.inspect}"

Render this highlighted source code:

    if n < 0: print 'Hello World!'

    if n < 0: print 'Hello World!'

    [true, false].cycle([0, 1, 2, 3, 4]) do |a, b|
        puts "#{a.inspect} => #{b.inspect}"

### Unnumbered source code listing

This source-highlight filtered block:

     [source,python]
     ---------------------------------------------------------------------
     ''' A multi-line
         comment.'''
     def sub_word(mo):
         ''' Single line comment.'''
         word = mo.group('word')   # Inline comment
         if word in keywords[language]:
             return quote + word + quote
         else:
             return word
     ---------------------------------------------------------------------

Renders this highlighted source code:

    ''' A multi-line
        comment.'''
    def sub_word(mo):
        ''' Single line comment.'''
        word = mo.group('word')     # Inline comment
        if word in keywords[language]:
            return quote + word + quote
        else:
            return word

### Numbered source code listing with callouts

This source-highlight filtered block:

     [source,ruby,numbered]
     ---------------------------------------------------------------------
     #
     # Useful Ruby base class extensions.
     #

     class Array

       # Execute a block passing it corresponding items in
       # +self+ and +other_array+.
       # If self has less items than other_array it is repeated.

       def cycle(other_array)  # :yields: item, other_item
         other_array.each_with_index do |item, index|
           yield(self[index % self.length], item)
         end
       end

     end

     if $0 == __FILE__                                 # <1>
       # Array#cycle test
       # true => 0
       # false => 1
       # true => 2
       # false => 3
       # true => 4
       puts 'Array#cycle test'                         # <2>
       [true, false].cycle([0, 1, 2, 3, 4]) do |a, b|
         puts "#{a.inspect} => #{b.inspect}"
       end
     end
     ---------------------------------------------------------------------

     <1> First callout.
     <2> Second callout.

Renders this highlighted source code:

    #
    # Useful Ruby base class extensions.
    #

    class Array

      # Execute a block passing it corresponding items in
      # +self+ and +other_array+.
      # If self has less items than other_array it is repeated.

      def cycle(other_array)  # :yields: item, other_item
        other_array.each_with_index do |item, index|
          yield(self[index % self.length], item)
        end
      end

    end

    if $0 == __FILE__                                 #
      # Array#cycle test
      # true => 0
      # false => 1
      # true => 2
      # false => 3
      # true => 4
      puts 'Array#cycle test'                         #
      [true, false].cycle([0, 1, 2, 3, 4]) do |a, b|
        puts "#{a.inspect} => #{b.inspect}"
      end
    end

First callout.

Second callout.

- If the source language attribute has been set (using an AttributeEntry or from the command-line) you don’t have to specify it in each source code block.

- You should place callout markers inside source code comments to ensure they are not misinterpreted and mangled by the highlighter.