Difference between revisions of "Custom pretty printer"

From Wiki
Jump to navigation Jump to search
(Document custom prettyprinters in MkIV)
 
m
 
(8 intermediate revisions by 2 users not shown)
Line 15: Line 15:
 
what to put in the file.
 
what to put in the file.
  
== Defining hooks ==
+
== Registering a new pretty printer ==
Each pretty printer should define a number of hook functions. Each of
+
To let the pretty printer core know about your pretty printer, you need
 +
to register it first. You do this by calling the
 +
<code>buffers.newvisualizer</code> 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 <code>\installprettytype</code>.
 +
 
 +
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 <code>visualizer</code> as the first
 +
component of the name (or whatever you assigned the return value from
 +
<code>newvisualizer</code> to).
 +
 
 +
For example, after registering the 'foo' prettyprinter as above, the
 +
<tt>flush_line</tt> 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
 
these will be called at specific times during the pretty printing and
are free to handle the input in any way. Each hook is optional, if it is
+
are free to handle the input in any way. See below for when and how a
not defined, a default version will be called instead.
+
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, the following hooks are called:
+
When pretty printing a file or buffer (named or anonymous using
 +
<code>\starttyping</code>), the following hooks are called:
  
 +
# Call <tt>begin_of_display</tt>
 
# For each line in the input:
 
# For each line in the input:
 
#* If the line contains only whitespace:
 
#* If the line contains only whitespace:
Line 31: Line 58:
 
#*# Call <tt>flush_line</tt> to process and output the current line.
 
#*# Call <tt>flush_line</tt> to process and output the current line.
 
#*# Call <tt>end_of_line</tt>
 
#*# Call <tt>end_of_line</tt>
 +
# Call <tt>end_of_display</tt>
  
Each hook should be defined as function named as follows:
+
When prettyprint a single phrase (using <code>\type</code>), the following
<tt>buffers.visualizers.''printer_name''.''function_name''</tt>
+
hooks are called:
  
For example, the <tt>flush_line</tt> function for the <tt>foo</tt>
+
# Call <tt>begin_of_inline</tt>
pretty printer, above should be defined as:
+
# Call <tt>flush_line</tt>
 +
# Call <tt>end_of_inline</tt>
  
  function buffers.visualizers.foo.flush_line(str,nested)
+
Note that in this case, the <tt>line</tt> hook is not called!
 
 
== Hooks ==
 
  
 
The following hooks are available to a pretty printer.
 
The following hooks are available to a pretty printer.
Line 46: Line 73:
 
===<tt>empty_line</tt>===
 
===<tt>empty_line</tt>===
  
   function buffers.visualizers.''printer_name''.empty_line()
+
   function visualizer.empty_line()
  
 
This hook is called for every empty line in the output. The default
 
This hook is called for every empty line in the output. The default
Line 54: Line 81:
 
===<tt>begin_of_line</tt>===
 
===<tt>begin_of_line</tt>===
  
   function buffers.visualizers.''printer_name''.begin_of_line(n)
+
   function visualizer.begin_of_line(n)
  
 
This hook is called at the start of every non-empty line. The only
 
This hook is called at the start of every non-empty line. The only
Line 72: Line 99:
 
===<tt>end_of_line</tt>===
 
===<tt>end_of_line</tt>===
  
   function buffers.visualizers.''printer_name''.end_of_line(n)
+
   function visualizer.end_of_line(n)
  
 
This hook is called at the end of every non-empty line. The function
 
This hook is called at the end of every non-empty line. The function
Line 83: Line 110:
 
===<tt>line</tt>===
 
===<tt>line</tt>===
  
   function buffers.visualizers.''printer_name''.line(str)
+
   function visualizer.line(str)
  
 
This hook is called for every non-empty line. The first argument is the
 
This hook is called for every non-empty line. The first argument is the
Line 97: Line 124:
 
===<tt>flush_line</tt>===
 
===<tt>flush_line</tt>===
  
   function buffers.visualizers.''printer_name''.flush_line(str, nested)
+
   function visualizer.flush_line(str, nested)
  
This hook is called for every non-empty line. The first argument is the
+
This hook is called for every non-empty line, or the entire content of
 +
an inline <code>\type</code> command. The first argument is the
 
line itself, as returned by the <tt>line</tt> hook. The second argument
 
line itself, as returned by the <tt>line</tt> hook. The second argument
 
is some indication of nested brackets in the input, but it's not
 
is some indication of nested brackets in the input, but it's not
Line 108: Line 136:
 
table and pass that to <tt>buffers.flush_result</tt> (which also handles
 
table and pass that to <tt>buffers.flush_result</tt> (which also handles
 
some stuff related to nesting).
 
some stuff related to nesting).
 +
 +
===<tt>begin_of_display, end_of_display, begin_of_inline, end_of_inline</tt>===
 +
 +
  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 <code>_display</code> versions are used when
 +
prettyprinting a buffer (named or anonymous using
 +
<code>\starttyping</code>) or a file. The <code>_inline</code> versions
 +
are used for prettyprinting a phrase inline, using <code>\type</code>.
 +
 +
These functions should return nothing, but can use <tt>texprint</tt> and
 +
friends to produce output.
 +
 +
The default implementations output some tex commands using
 +
<tt>buffers.commands.{begin,end}_of_{display,inline}_command</tt> (which
 +
seem to expand to nothing currently).
  
 
== Utility functions and variables ==
 
== Utility functions and variables ==
Line 123: Line 171:
 
The above is not quite complete, some things are missing or
 
The above is not quite complete, some things are missing or
 
underdocumented. The code that drives the prettyprinting is in the file
 
underdocumented. The code that drives the prettyprinting is in the file
<tt>buff-ini.lua</tt> (which is called by <tt>buff-ini.mkiv</tt> and
+
[[source:buff-ini.lua|buff-ini.lua]] (which is called by [[source:buff-ini.mkiv|buff-ini.mkiv]] and
<tt>buff-ver.mkiv</tt> from the TeX side), in the ConTeXt distribution.
+
[[source:buff-ver.mkiv|buff-ver.mkiv]] from the TeX side), in the ConTeXt distribution.
 
If you're missing anything, you'll probably find some answers there.
 
If you're missing anything, you'll probably find some answers there.
 
Don't forget to write down what you find on this page!
 
Don't forget to write down what you find on this page!
 +
 +
[[Category:Old_Content]]

Latest revision as of 14:08, 8 June 2020

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