Basic example of LuaTeX’s process_input_buffer callback

Introduction

As mentioned in a previous post, LuaTeX provides a facility called callbacks in which you write a Lua function (your callback) and register it with LuaTeX through the callback.register() API function.

callback.register() takes two parameters:

  • A predefined callback name: as defined by LuaTeX. This defines the action or purpose of your of function and is the “hook” into LuaTeX telling it where/why/when your function should be called.
  • Your actual callback function: either a named or anonymous Lua function.

In this post I’ll give an example/framework for one simple way to use the process_input_buffer callback. This callback allows you to hook into LuaTeX’s input buffer before LuaTeX actually starts looking at it. With this callback you can, for example, completely re-process the input and return the processed results back to LuaTeX, or filter out entire sections of the input–perhaps to store it elsewhere for later use or processing.

Code example and explanation

We will register a callback function which strips out the input sandwiched between two macros called \startbuffer{..} and \stopbuffer. Again, this is a simple example and there are undoubtedly many much more sophisticated ways to do this.

The basic idea here is that the macro

\def\startbuffer#1{%
\directlua{
     dosomething(#1)
     callback.register("process_input_buffer",dobuffer)}
}

switches on intercepting the input, and a dummy macro (\stopbuffer{}) is “intercepted” to switch off processing the input.

There’s a very important point here in that after we make a call to \startbuffer{…} all our input bypasses LuaTeX processing from that point on and is passed to the function we have registered: “dobuffer”. To detect the end of the buffer, and switch off the callback, dobuffer must scan the input for the string “stopbuffer” and “unregister” the callback so that LuaTeX reverts back to its standard processing of the input. For sure, this approach could fail if the string stopbuffer occurs elsewhere within the input stream. I did say it was a simple example ;-).

In the example you can see a string of characters ” ^ & # _ $$ % \” whose \catcode settings could, without their \catcode being reset temporarily, cause problems if input and processed directly by LuaTeX.

\startbuffer{figure1}
Let’s have some characters with various catcodes:
^
&
#
_
$$
%
\
\stopbuffer

However, in the example these characters are being intercepted long before LuaTeX starts to process them and so the idea of catcodes, at this point, has no meaning. Of course, they can still trip you up later in your processing.

Explanation

After the call to \startbuffer{…}, every line in the input is passed to the function dobuffer() which in our example does very little except print it out to the screen. Because the dobuffer() function returns the empty string “” the entire input between \startbuffer and \stopbuffer is removed from LuaTeX’s input: it never reaches the typesetting engine. You could use this as a simple way to implement long comment sections in your document.

You could implement the dobuffer function to perform all sorts of tasks, such as save a copy of the filtered input and store it into, say, a table perhaps indexed by the value passed into \startbuffer{…..}. The options and possibilities are endless!

\pdfoutput=1
\hoffset-1in
\voffset-1in
\pdfpagewidth=100mm
\pdfpageheight=100mm

\directlua{

function addline(line)
     print("I was called with "..line)
end}

\directlua{

function dobuffer(line)
   if string.match(line,"stopbuffer") then
	callback.register("process_input_buffer",nil)
	return ""
   end
	addline(line)
	return "" % this removes line from LuaTeX's input buffer
end
}

\directlua{
	function dosomething(str)
	% do something useful with the parameter to \startbuffer{.....}
	end
}

\def\startbuffer#1{\directlua{dosomething(#1);callback.register("process_input_buffer",dobuffer)}}
\def\stopbuffer{}

\startbuffer{figure1}
Let's have some characters with various catcodes:
^
&
#
_ 
$$ 
% 
\
\stopbuffer

Hello

\bye

One thought on “Basic example of LuaTeX’s process_input_buffer callback

  1. Pingback: Producing printers crop marks with MetaPost and LuaTeX nodes « STM publishing: tools, technologies and change

Comments are closed.