% language=us runpath=texruns:manuals/cld

\startcomponent cld-moreonfunctions

\environment cld-environment

\startchapter[title=More on functions]

\startsection[title=Why we need them]

\index{functions}

In a previous chapter we introduced functions as arguments. At first sight this
feature looks strange but you need to keep in mind that a call to a \type
{context} function has no direct consequences. It generates \TEX\ code that is
executed after the current \LUA\ chunk ends and control is passed back to \TEX.
Take the following code:

\startbuffer
context.framed( {
    frame = "on",
    offset = "5mm",
    align = "middle"
  },
  context.input("knuth")
)
\stopbuffer

\typebuffer

We call the function \type {framed} but before the function body is executed, the
arguments get evaluated. This means that \type {input} gets processed before
\type {framed} gets done. As a result there is no second argument to \type
{framed} and no content gets passed: an error is reported. This is why we need
the indirect call:

\startbuffer
context.framed( {
    frame = "on",
    align = "middle"
  },
  function() context.input("knuth") end
)
\stopbuffer

\typebuffer

This way we get what we want:

\startlinecorrection
\ctxluabuffer
\stoplinecorrection

The function is delayed till the \type {framed} command is executed. If your
applications use such calls a lot, you can of course encapsulate this ugliness:

\starttyping
mycommands = mycommands or { }

function mycommands.framed_input(filename)
  context.framed( {
    frame = "on",
    align = "middle"
  },
  function() context.input(filename) end
end

mycommands.framed_input("knuth")
\stoptyping

Of course you can nest function calls:

\starttyping
context.placefigure(
  "caption",
  function()
    context.framed( {
      frame = "on",
      align = "middle"
    },
      function() context.input("knuth") end
    )
  end
)
\stoptyping

Or you can use a more indirect method:

\starttyping
function text()
  context.framed( {
      frame = "on",
      align = "middle"
    },
    function() context.input("knuth") end
  )
end

context.placefigure(
  "none",
  function() text() end
)
\stoptyping

You can develop your own style and libraries just like you do with regular \LUA\
code. Browsing the already written code can give you some ideas.

\stopsection

\startsection[title=How we can avoid them]

\index{delaying}
\index{nesting}

As many nested functions can obscure the code rather quickly, there is an
alternative. In the following examples we use \type {test}:

\startbuffer
\def\test#1{[#1]}
\stopbuffer

\typebuffer \getbuffer

\startbuffer
context.test("test 1 ",context("test 2a")," test 3")
\stopbuffer

\typebuffer

This gives: \ctxluabuffer. As you can see, the second argument is executed before
the encapsulating call to \type {test}. So, we should have packed it into a
function but here is an alternative:

\startbuffer
context.test("test 1 ",context.delayed("test 2a")," test 3")
\stopbuffer

\typebuffer

Now we get: \ctxluabuffer. We can also delay functions themselves,
look at this:

\startbuffer
context.test("test 1 ",context.delayed.test("test 2b")," test 3")
\stopbuffer

\typebuffer

The result is: \ctxluabuffer. This feature also conveniently permits the use of
temporary variables, as in:

\starttyping
local f = context.delayed.test("test 2c")
context("before ",f," after")
\stoptyping

Of course you can limit the amount of keystrokes even more by
creating a shortcut:

\starttyping
local delayed = context.delayed

context.test("test 1 ",delayed.test("test 2")," test 3")
context.test("test 4 ",delayed.test("test 5")," test 6")
\stoptyping

So, if you want you can produce rather readable code and readability of code is
one of the reasons why \LUA\ was chosen in the first place. This is a good
example of why coding in \TEX\ makes sense as it looks more intuitive:

\starttyping
\test{test 1 \test{test 2} test 3}
\test{test 4 \test{test 5} test 6}
\stoptyping

The \type {context.nested} variant is now an alias to \type {context.delayed} and
no longer builds a string representation.

% There is also another mechanism available. In the next example the second
% argument is actually a string.
%
% \starttyping
% local nested = context.nested
%
% context.test("test 8",nested.test("test 9"),"test 10")
% \stoptyping
%
% There is a pitfall here: a nested context command needs to be flushed explicitly,
% so in the case of:
%
% \starttyping
% context.nested.test("test 9")
% \stoptyping
%
% a string is created but nothing ends up at the \TEX\ end. Flushing is up to you.
% Beware: \type {nested} only works with the regular \CONTEXT\ catcode regime.

\stopsection

\startsection[title=Trial typesetting]

\index {prerolls}
\index {trial typesetting}

Some typesetting mechanisms demand a preroll. For instance, when determining the
most optimal way to analyse and therefore typeset a table, it is necessary to
typeset the content of cells first. Inside \CONTEXT\ there is a state tagged
\quote {trial typesetting} which signals other mechanisms that for instance
counters should not be incremented more than once.

Normally you don't need to worry about these issues, but when writing the code
that implements the \LUA\ interface to \CONTEXT, it definitely had to be taken
into account as we either or not can free cached (nested) functions.

You can influence this caching to some extend. If you say

\starttyping
function()
  context("whatever")
end
\stoptyping

the function will be removed from the cache when \CONTEXT\ is not in the trial
typesetting state. You can prevent removal of a function by returning \type
{true}, as in:

\starttyping
function()
  context("whatever")
  return true
end
\stoptyping

Whenever you run into a situation that you don't get the outcome that you expect,
you can consider returning \type {true}. However, keep in mind that it will take
more memory, something that only matters on big runs. You can force flushing the
whole cache by:

\starttyping
context.restart()
\stoptyping

An example of an occasion where you need to keep the function available is in
repeated content, for instance in headers and footers.

\starttyping
context.setupheadertexts {
  function()
    context.pagenumber()
    return true
  end
}
\stoptyping

Of course it is not needed when you use the following method:

\starttyping
context.pagenumber("pagenumber")
\stoptyping

Because here \CONTEXT\ itself deals with the content driven by the keyword \type
{pagenumber}.

\stopsection

\startsection[title=Steppers]

The \type {context} commands are accumulated within a \type {\ctxlua} call and
only after the call is finished, control is back at the \TEX\ end. Sometimes you
want (in your \LUA\ code) to go on and pretend that you jump out to \TEX\ for a
moment, but come back to where you left. The stepper mechanism permits this.

A not so practical but nevertheless illustrative example is the following:

\startbuffer
\startluacode
  context.stepwise (function()
    context.startitemize()
       context.startitem()
         context.step("BEFORE 1")
       context.stopitem()
       context.step("\\setbox0\\hbox{!!!!}")
       context.startitem()
         context.step("%p",tex.getbox(0).width)
       context.stopitem()
       context.startitem()
         context.step("BEFORE 2")
       context.stopitem()
       context.step("\\setbox2\\hbox{????}")
       context.startitem()
         context.step("%p",tex.getbox(2).width)
       context.startitem()
         context.step("BEFORE 3")
       context.stopitem()
       context.startitem()
         context.step("\\copy0\\copy2")
       context.stopitem()
       context.startitem()
         context.step("BEFORE 4")
         context.startitemize()
           context.stepwise (function()
             context.step("\\bgroup")
             context.step("\\setbox0\\hbox{>>>>}")
             context.startitem()
               context.step("%p",tex.getbox(0).width)
             context.stopitem()
             context.step("\\setbox2\\hbox{<<<<}")
             context.startitem()
               context.step("%p",tex.getbox(2).width)
             context.stopitem()
             context.startitem()
               context.step("\\copy0\\copy2")
             context.stopitem()
             context.startitem()
               context.step("\\copy0\\copy2")
             context.stopitem()
             context.step("\\egroup")
           end)
         context.stopitemize()
       context.stopitem()
       context.startitem()
         context.step("AFTER 1\\par")
       context.stopitem()
       context.startitem()
         context.step("\\copy0\\copy2\\par")
       context.stopitem()
       context.startitem()
         context.step("\\copy0\\copy2\\par")
       context.stopitem()
       context.startitem()
         context.step("AFTER 2\\par")
       context.stopitem()
       context.startitem()
         context.step("\\copy0\\copy2\\par")
       context.stopitem()
       context.startitem()
         context.step("\\copy0\\copy2\\par")
       context.stopitem()
     context.stopitemize()
end)
\stopluacode
\stopbuffer

\typebuffer

This gives an (ugly) itemize with a nested one:

\getbuffer

As you can see in the code, the \type {step} call accepts multiple arguments, but
when more than one argument is given the first one is treated as a formatter.

\stopsection

\stopchapter

\stopcomponent
