I'm working towards creating a lualatex-based package that lets users automatically suppress the use of ligatures (for now, ff, fi, fl, ffi, ffl, and ft) for selected words. (For background see this question.) The package is set to work with both English and German language words. The MWE below, which is a very much stripped down version of the package, shows how to suppress the insertion of ligatures for four selected words -- two English, two German. (The correct hyphenation of the selected words -- both at the non-ligation points and potentially elsewhere in the words -- is also taken care of. The little red dashes in the output image, generated by of the showhyphens package, indicate where LuaLaTeX thinks it's OK to insert hyphenation breaks.)
Here's the problem I'm trying to solve: The package's main routine (implemented as a lua callback function that operates on process_input_buffer) turns out to be way too greedy for its own good: It tries to perform string substitution operations on everything in the input buffer, including the names and arguments of TeX macros. To make the package suitable for field work, I have to find a way to prevent the main text translation macro from operating on
- string snippets that are parts of TeX macros and on
- the arguments of select instructions, such as
\label
and\ref
.
(There are probably other cases where the substitution shouldn't be applied either.)
Are there any conditionals -- or how might one go about creating such conditionals? -- to check if a string for which a match is found is part of either an already-defined macro or an argument of a \label
or \ref
(or \varioref
, \cref
, etc) macro? Alternatively, how might one prevent outright the substitution macro from operating on (i) any TeX macros and (ii) the arguments of selected macros?
A couple of quick illustrations of these problems:
Suppose that there's a macro in a document named named
\bookshelfful
. (Not exactly likely, of course, but this is just meant to provide an example.) For such a macro, I don't want my macro operating on it, as it would end up being transformed into\bookshelf \nobreak\hskip0pt \discretionary{\char\hyphenchar\font}{}{\kern\KERN} \nobreak\hskip0pt ful
. Arggh.Should there be a label in the document named "
thm:cufflinks
" (yeah, sure!), it must not get translated into "thm:cuff\nobreak\hskip0pt \discretionary{\char\hyphenchar\font}{}{\kern\KERN} \nobreak\hskip0pt links
".
Double arrgh.
% !TEX TS-program = lualatex
\documentclass[12pt]{article}
\usepackage[margin=1in]{geometry}
\usepackage[no-math]{fontspec}
%% work around a bug in luaotfload (cf. https://tex.stackexchange.com/q/47031/5001)
\setmainfont[Renderer=Basic]{Latin Modern Roman}
\defaultfontfeatures{Ligatures={TeX,Common}}
\usepackage{showhyphens} % show all hyphenation points
\usepackage{luatexbase,luacode}
\begin{luacode*}
do
local replace = {}
local filter = function ( buf )
for key, val in pairs ( replace ) do
buf = string.gsub ( buf, key, val )
end
return buf
end
function translateinput ( arg1,arg2 ) -- with discretionary hyphen
replace[arg1]=string.gsub(arg2,"|%*|",[[\kernandhyph ]])
end
function enablefilters()
luatexbase.add_to_callback('process_input_buffer', filter, 'filter')
end
end
\end{luacode*}
\newcommand\enableinputtranslation{
\directlua{
enablefilters()
}
}
\newcommand{\kernandhyph}{%
\nobreak\hskip0pt%
\discretionary{\char\hyphenchar\font}{}{\kern\KERN}%
\nobreak\hskip0pt%
}
\newcommand\translateinput[2]{
\directlua{
translateinput ( "\luatexluaescapestring{#1}",
"\luatexluaescapestring{#2}" )
}
}
% some substitution rules
\translateinput{lfful}{lf|*|ful} %% e.g., shelf-ful(s) bookshelf-ful(s)
\translateinput{fflink}{ff|*|link} %% cuff-link(s)
\translateinput{iflich}{if|*|lich} %% reif-lich begreif-lich tarif-lich
\translateinput{uflauf}{uf|*|lauf} %% auf-laufen
\translateinput{ufform}{uf|*|form} %% auf-formen
\newlength\KERN
\setlength\KERN{0.07ex} % trial value for amount of kern to be inserted
\begin{document}
shelfful cufflink unbegreiflich Auflaufform
\quad \emph{versus}
\enableinputtranslation % turn on input translation
shelfful cufflink unbegreiflich Auflaufform
\end{document}
\ref
, whose contents should be left intact. I think that this problem ought to be solved during the typesetting phase and not the parsing/interpreting phase of the LaTeX run.pre_linebreak_filter
should be used. Perhaps one day I'll post another solution to the original question...\label
and\ref
, I'll be ready to release the package in beta form to the CTAN -- an event that will, no doubt, prompt much more debugging...