Custom pretty printer

From Wiki
Jump to navigation Jump to search

< Verbatim_text

Custom pretty printers

ConTeXt allows one to define a custom pretty printer, which knows how to interpret and display a particular type of file, text or programming language.

This page details the creation of a pretty printer in Lua, which is possible with MkIV and LuaTeX. This page does not apply to MkII.

To create a custom pretty printer, you need to create a file named pret-foo.lua, where foo is the name of the prettyprinter. Fore more details about where to put this file and how to use it, see Verbatim_text#Your_own_formatter. We'll focus here on what to put in the file.

Registering a new pretty printer

To let the pretty printer core know about your pretty printer, you need to register it first. You do this by calling the buffers.newvisualizer function:

 local visualizer = buffers.newvisualizer('foo')

Here, you pass the name of the pretty printer, which is the (lowercase) version of the first argument to \installprettytype.

This function returns an (empty) table, into which you should store the hook functions for any hooks you want to override. You can do this by simply declaring the function with visualizer as the first component of the name (or whatever you assigned the return value from newvisualizer to).

For example, after registering the 'foo' prettyprinter as above, the flush_line hook should be defined as:

 function visualizer.flush_line(str,nested)

Each pretty printer can define a number of hook functions. Each of these will be called at specific times during the pretty printing and are free to handle the input in any way. See below for when and how a hook is called. Defining a hook is optional, if it is not defined, a default version will be called instead.

Hooks

This section lists all hooks available to a pretty printer. First we'll show how and when the hooks are called.

When pretty printing a file or buffer (named or anonymous using \starttyping), the following hooks are called:

  1. Call begin_of_display
  2. For each line in the input:
    • If the line contains only whitespace:
      1. Call empty_line
    • Else:
      1. Call begin_of_line
      2. Call line to modify the current line.
      3. Call flush_line to process and output the current line.
      4. Call end_of_line
  3. Call end_of_display

When prettyprint a single phrase (using \type), the following hooks are called:

  1. Call begin_of_inline
  2. Call flush_line
  3. Call end_of_inline

Note that in this case, the line hook is not called!

The following hooks are available to a pretty printer.

empty_line

 function visualizer.empty_line()

This hook is called for every empty line in the output. The default implementation just outputs an empty line, using the buffers.commands.empty_line_command.

begin_of_line

 function visualizer.begin_of_line(n)

This hook is called at the start of every non-empty line. The only argument, n, is the number of the line. The function should return nothing (but use texprint and friends to produce output).

The default implementation outputs an optional line number and some other tex commands, using buffers.commands.begin_of_line_command.

Note that the line number does not include empty lines. This is configurable using the flags.count_empty_lines variable, although there does not seem to be a way to set this flag using a ConTeXt macro.

end_of_line

 function visualizer.end_of_line(n)

This hook is called at the end of every non-empty line. The function should return nothing (but use texprint and friends to produce output).

The default implementation outputs some tex commands using buffers.commands.end_of_line_command.

line

 function visualizer.line(str)

This hook is called for every non-empty line. The first argument is the line itself,. The function should return an updated line, which is then passed to flush_line.

The default implementation just returns its argument unmodified.

It's not exactly clear to me what the purpose of this hook is. None of the existing pretty printers seem to use it, they all do their work in flush_line.

flush_line

 function visualizer.flush_line(str, nested)

This hook is called for every non-empty line, or the entire content of an inline \type command. The first argument is the line itself, as returned by the line hook. The second argument is some indication of nested brackets in the input, but it's not completely clear how this works.

The function should return nothing, but use texprint and friends to produce output. Alternatively, the function could build a table and pass that to buffers.flush_result (which also handles some stuff related to nesting).

begin_of_display, end_of_display, begin_of_inline, end_of_inline

 function visualizer.begin_of_display()
 function visualizer.end_of_display()
 function visualizer.begin_of_inline()
 function visualizer.end_of_inline()

These hooks are called at the start and end of prettyprinting a buffer, file or phrase. The _display versions are used when prettyprinting a buffer (named or anonymous using \starttyping) or a file. The _inline versions are used for prettyprinting a phrase inline, using \type.

These functions should return nothing, but can use texprint and friends to produce output.

The default implementations output some tex commands using buffers.commands.{begin,end}_of_{display,inline}_command (which seem to expand to nothing currently).

Utility functions and variables

There are some utilities available for pretty printers. All of the below are defined in buff-ini.lua, as well as some other stuff not listed here.

buffers.flush_result(result, nested)
Output all values in the given table result, while doing something with nesting.
buffers.change_state(n, state)
Set the current color to n, given the current color state. Returns the new color state.
buffers.finish_state(state)
Reset the current color, given the current color state. Returns the new color state.
buffers.currentcolors
This is a table that maps color numbers (as passed to buffer.change_state) to TeX color names. A pretty printer using coloring should set this in its flush_line, for example.
buffers.commands
This variable contains a number of useful TeX commands. See buff-ini.lua for details.

More info

The above is not quite complete, some things are missing or underdocumented. The code that drives the prettyprinting is in the file buff-ini.lua (which is called by buff-ini.mkiv and buff-ver.mkiv from the TeX side), in the ConTeXt distribution. If you're missing anything, you'll probably find some answers there. Don't forget to write down what you find on this page!