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:

. The 'language' attribute is set to the AsciiDoc 'language'
  attribute.
. 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'):

NOTE: 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
https://www.gnu.org/software/src-highlite/[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
http://www.andre-simon.de/doku/highlight/en/highlight.html[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 https://pygments.org/[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.
+
NOTE: 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:

[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}"


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:

[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
---------------------------------------------------------------------

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:

[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.

[TIP]
=====
- 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.
=====
