4

I'm typesetting a text in which I want to add space before double punctuation using LuaLaTeX.


To give you the idea: Using this answer and this one, I wrote following code which do not work (for "Test!" it returns "Test0.1em!" and I did expect "Test !")

\def\dblpnct#1{\unskip\noexpand\hspace{0.1em}#1}
\usepackage{luacode}
\begin{luacode}
function dosub(s)
    s = string.gsub(s, '!', '\\dblpnct!')
    s = string.gsub(s, ':', '\\dblpnct:')
    s = string.gsub(s, ';', '\\dblpnct;')
    s = string.gsub(s, '?', '\\dblpnct?')
    return(s)
end
\end{luacode}
\AtBeginDocument{%
    \luaexec{luatexbase.add_to_callback("process_input_buffer", dosub, "dosub")}%
}

2 Answers2

5

\noexpand is the culprit. But removing it is not the full answer.

There's no reason for defining \dblpnct with an argument, but this is not a real problem.

If you are implementing French style spacing before double punctuation, you should be aware that the colon obeys different rules: it should be preceded and followed by a normal interword space. But most important is that you don't want the added space is a feasible line break point.

Defensive code requires also that \unskip is only issued if we're in horizontal mode.

\documentclass{article}
\usepackage{luacode}
\usepackage{etoolbox}

\newrobustcmd\dblpnct[1]{%
  \ifhmode\unskip\fi
  \nolinebreak#1%
}
\begin{luacode}
function dosub(s)
    s = string.gsub(s, '!', '\\dblpnct{\\hspace{0.1em}}!')
    s = string.gsub(s, ':', '\\dblpnct{\\space}:')
    s = string.gsub(s, ';', '\\dblpnct{\\hspace{0.1em}};')
    s = string.gsub(s, '?', '\\dblpnct{\\hspace{0.1em}}?')
    return(s)
end
\end{luacode}

\AtBeginDocument{%
  \luaexec{luatexbase.add_to_callback("process_input_buffer", dosub, "dosub")}%
}

\begin{document}

Some text ! Or is it a question ? The colon : obeys different ; rules.

Some text! Or is it a question? The colon: obeys different; rules.

\end{document}

enter image description here

And you should also disable this in math mode, or the spacing will be definitely wrong.

\documentclass{article}
\usepackage{luacode}
\usepackage{etoolbox}

\newrobustcmd\dblpnct[1]{%
  \ifmmode\else
    \ifhmode\unskip\fi
    \nolinebreak#1%
  \fi
}
\begin{luacode}
function dosub(s)
    s = string.gsub(s, '!', '\\dblpnct{\\hspace{0.1em}}!')
    s = string.gsub(s, ':', '\\dblpnct{\\space}:')
    s = string.gsub(s, ';', '\\dblpnct{\\hspace{0.1em}};')
    s = string.gsub(s, '?', '\\dblpnct{\\hspace{0.1em}}?')
    return(s)
end
\end{luacode}

\AtBeginDocument{%
  \luaexec{luatexbase.add_to_callback("process_input_buffer", dosub, "dosub")}%
}

\begin{document}

Some text ! Or is it a question ? The colon : obeys different ; rules.

Some text! Or is it a question? The colon: obeys different; rules.

Oh, what about math ? $a:b$ and $(a;b)$

\end{document}

Check the result if you remove the \ifmmode conditional.

enter image description here

In order to disable the behavior in the argument to \label and \ref, you can use \ifincsname, but this requires changing the definition of \label.

\documentclass{article}
\usepackage{luacode}
\usepackage{etoolbox}

\newrobustcmd\dblpnct[1]{%
  \ifincsname
  \else
    \ifmmode\else
      \ifhmode\unskip\fi
      \nolinebreak#1%
    \fi
  \fi
}
\makeatletter
% latex.ltx, line 4070:
\def\label#1{\@bsphack
  \protected@write\@auxout{\let\dblpnct\@gobble}% <-- disable in \label
         {\string\newlabel{#1}{{\@currentlabel}{\thepage}}}%
  \@esphack}
\makeatother

\begin{luacode}
function dosub(s)
    s = string.gsub(s, '!', '\\dblpnct{\\hspace{0.1em}}!')
    s = string.gsub(s, ':', '\\dblpnct{\\space}:')
    s = string.gsub(s, ';', '\\dblpnct{\\hspace{0.1em}};')
    s = string.gsub(s, '?', '\\dblpnct{\\hspace{0.1em}}?')
    return(s)
end
\end{luacode}

\AtBeginDocument{%
  \luaexec{luatexbase.add_to_callback("process_input_buffer", dosub, "dosub")}%
}

\begin{document}

Some text ! Or is it a question ? The colon : obeys different ; rules.

Some text! Or is it a question? The colon: obeys different; rules.

Oh, what about math ? $a:b$ and $(a;b)$

Here's a reference to page~\pageref{page:x}\label{page:x}.

\end{document}
egreg
  • 1,121,712
3

As I noted in a comment: Simply removing \noexpand from the OP's code works.

  • Evidently there is a way to markup inline code, but I didn't see how. Care to enlighten me? If there is a link to the code, I didn't readily find it on the page. I had tried putting it on a separate line with spaces in front, but that didn't work. –  Oct 07 '16 at 02:14
  • Put backticks around it. If you just edit your post, you'll see how it is done for yourself. – cfr Oct 11 '16 at 00:44