3

In order to simplify some of the LaTeX work for my co-authors, I have created a custom environment which sets up a tabular. This reads the input from the environment, processes it and spits it back out in TeX. My issue here is I do not seem to get the input escaped before passing it to Lua. I have a minimal example below.

The result in the custom environment is that "\" seem to miss from the input stored in the Lua buffer (Or rather, it gets "\S" and removed the backslash since it is not a recognized escape sequence). Is there a special call I need to make in order to get Lua to escape the text before it attempts to parse it?

On a side note I have trouble matching the end statement for the environment in Lua. I can only seem to match on the initial part. This may be related to lacking escape sequences.

The LaTeX file ("document.tex")

\documentclass[a4paper,openany,oneside]{memoir}

\usepackage{luacode}
\usepackage{siunitx}

\luadirect{dofile("env.lua")}

\newenvironment{test-env}
{
    % Register the callback.
    \luadirect{test_start_recording()}
}
{
    % Remove the callback.
    \luadirect{test_stop_recording()}
}

\begin{document}
\noindent Test document in normal TeX mode: \SI{30}{s}.
\begin{test-env}
Line 1 \\
\SI{30}{s} \\
Line 3
\end{test-env}

\end{document}

And for the lua file ("env.lua")

local end_verb_orig = "%s*\\end{test-env}"
local end_verb = "%s*\\end{"

mybuf = ""

function trim(s)
  return s:match'^%s*(.*%S)' or ''
end

function test_readbuf( buf )
  if buf:find(end_verb) then
    return buf
  end

  mybuf = mybuf .. buf .. "\n"

  return ""
end

function test_start_recording()
  -- Register callback to catch the input.
  luatexbase.add_to_callback('process_input_buffer', test_readbuf, 'test_readbuf')
end

function test_stop_recording()
  -- Remove callback.
  luatexbase.remove_from_callback('process_input_buffer', 'test_readbuf')

  -- Print the result.
  test_print()
end

function test_print()
  -- Iterate over all the lines in the buffer. We match on the TeX linebreaks.
  for line in mybuf:gmatch("[^\\\\]+") do
    test_print_line(line)
  end

  -- Reset variables.
  mybuf = ""
end

function test_print_line(line)
  -- Trim whitespace.
  line = trim(line)

  -- If the line is empty, do nothing.
  if line == "" then
    return
  end

  -- Here Lua magic may happen.

  -- Print the result.
  tex.print(line .. "\\\\")
end

Edit It seems that it is the way I match the linebreaks is to blame. Using texio.write(line) as per recommendation from topskip in the comments.

  • The for line in mybuf:gmatch(...) is wrong. Use texio.write_nl(mybuf) before that line and texio.write_nl(line) right after that line. The match strips the backslash. – topskip Apr 18 '16 at 7:25
  • I tried editing the code but I'm a bit unsure of where you would like me to insert the texio lines. I've edited my question with what I attempted, but the end result is still the same. – mgs Apr 18 '16 at 7:34
  • Sorry, I meant that you can use the texio.write_nl() lines to debug the output (it gets written to the console). – topskip Apr 18 '16 at 7:48
  • Ah, I will see if I can get somewhere with that. My current assumption is something goes wrong with regards to the internal process_input_buffer. – mgs Apr 18 '16 at 7:55
  • As I said: the contents of mybuf is fine, the lines in the loop do not contain the backslash (function test_print()). – topskip Apr 18 '16 at 8:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.