# Automatically adding space before punctuation in LuaLaTeX

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{%
}

• Try removing \noexpand. Works for me. – user103221 Oct 6 '16 at 16:51
• your lua works but you have added something equivalent to \unskip\relax{0.1em}! so it just typesets 0.1em – David Carlisle Oct 6 '16 at 17:48
• @RobtA do you want to make the comment an answer? – David Carlisle Oct 6 '16 at 17:56
• French style spaces around colons obey different rules than semicolon, question mark and exclamation mark. Around the colon there should be normal interword spaces. Instead of \noexpand you should have \nolinebreak. – egreg Oct 6 '16 at 22:13
• You should look at how babel-frenchb does it. – user4686 Oct 7 '16 at 21:55

\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{%
}

\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}


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{%
}

\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.

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{%
}

\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}

• Is there a way to avoid substitution taking place in labels? I have \label{eq:test} and it produces errors. – Kyle_the_hacker Oct 7 '16 at 8:20
• @Kyle_the_hacker There should be; I'll check on it later. – egreg Oct 7 '16 at 8:23
• @Kyle_the_hacker I added how to cope with \label and \ref. – egreg Oct 7 '16 at 17:45
• related issue – Kyle_the_hacker Oct 10 '16 at 23:50
• another related issue – Kyle_the_hacker Oct 27 '16 at 21:23

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. – user103221 Oct 7 '16 at 2: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 0:44