1

I noticed a strange interaction between the fontspec package and lua code. I have been using for some time a lua code found on this site that prevents words composed of a single letter ("a", "à" and "y" in French) from being found "alone" at the end of a line.

Surprisingly, if I load a font with fontspec, use this lua code, and one of the chapters starts with one of these one-letter words, the running title in the header is not composed in small caps as it should be.

If I do not load a new font or activate the lua code, the problem does not appear. The problem only appears in the header, if I type for example simply \textsc{A ...}, there is no problem.

This is very strange, I don't understand what is going on at all. Do you have any idea?

Example: on the left a header with a chapter name beginning with "a" which is not small-capitalized; on the right a normal header:
enter image description here enter image description here

\documentclass{book}
\usepackage{lipsum, luacode, fontspec}
\setmainfont{LibertinusSerif}

\begin{luacode}
local GLYPH = node.id("glyph")
local GLUE = node.id("glue")
local prevent_single_letter = function (head)
    while head do
        if (head.id == GLYPH) then
            if unicode.utf8.match(unicode.utf8.char(head.char), "[aAàÀyY]") then
                if ((head.prev.id == GLUE
                    or (head.prev.id == GLYPH
                        and unicode.utf8.match(unicode.utf8.char(head.prev.char), "[%[%]()%{%}]")))
                        and head.next.id == GLUE) then
                    local p = node.new("penalty")
                    p.penalty = 10000
                    node.insert_after(head, head, p)
                end
            end
        end
        head = head.next
    end
    return true
end
function single_letter_enable ()
    luatexbase.add_to_callback("pre_shaping_filter", prevent_single_letter, "singleletter")
end
\end{luacode}
\directlua{single_letter_enable()}

\makeatletter
\def\ps@headings{
    \def\@evenhead{{\scshape\rightmark}\hfil}
    \def\chaptermark##1{\markright{##1}}
}
\makeatother
\pagestyle{headings}

\begin{document}
\chapter*{A test}\chaptermark{A test}
\lipsum[1-7]

\chapter*{Test}\chaptermark{Test}
\lipsum[1-7]

\textsc{A test}
\end{document}

Edit

On the proposal of user187802, the lua code has been modified.

\documentclass{book}

\usepackage{lipsum, luacode, fontspec}
\setmainfont{LibertinusSerif}

\begin{luacode}
local GLYPH = node.id("glyph")
local GLUE = node.id("glue")
local prevent_single_letter = function (head)
    while head do
        if (head.id == GLYPH) then
          if head.prev then.    --  !!!!!!!
            if unicode.utf8.match(unicode.utf8.char(head.char), "[aAàÀyY]") then -- and head.prev.id ~= GLUE  then
                if ((head.prev.id == GLUE
                        or (head.prev.id == GLYPH
                            and unicode.utf8.match(unicode.utf8.char(head.prev.char), "[%[%]()%{%}]")))
                            and head.next.id == GLUE) then
                        local p = node.new("penalty")
                        p.penalty = 10000
                        node.insert_after(head, head, p)
                    end
                end
            end
        end
        head = head.next
    end
    return true
end
function single_letter_enable ()
    luatexbase.add_to_callback("pre_shaping_filter", prevent_single_letter, "singleletter")
end
\end{luacode}

\directlua{single_letter_enable()}

\makeatletter
\def\ps@headings{
    \def\@evenhead{{\scshape\rightmark}\hfil}
    \def\chaptermark##1{\markright{##1}}
}
\makeatother
\pagestyle{headings}

\begin{document}
Le titre courant est un rappel du titre de l’ouvrage, du chapitre, parfois abrégé, a % "a" should not be alone at the end of the line, but should be sent to the next line
placé dans la marge supérieure ou inférieure d’une page.

\chapter*{A test}\chaptermark{A test}
\lipsum[1-7]

\chapter*{Test}\chaptermark{Test}
\lipsum[1-7]
\end{document}

However the code does not seem to do what it was created for anymore. For example in the text below, the word "a" should not be alone at the end of the line, it should be pushed to the beginning of the next line.

enter image description here

4
  • The code throws an error after the first chapter. After an error message has been issues the output should never be relied upon. Commented Dec 11, 2021 at 19:39
  • Hello, thank you for your reply. In Texmaker, I don't have any errors (except for the following warning, which is unrelated to the problem: Package lipsum Warning: Unknown language 'latin'. Hyphenation patterns for (lipsum) 'english' will be used instead.). :/
    – Bastien
    Commented Dec 11, 2021 at 19:48
  • I get a clear error in texlive 2021: warning (hpack filter): error: [\directlua]:7: attempt to index a nil value (field 'prev') Commented Dec 11, 2021 at 19:53
  • Oh yes indeed, I saw an error message after reading the log file. However, it is not displayed by Texmaker and MikTex. I'm not sure what to make of it...
    – Bastien
    Commented Dec 11, 2021 at 19:56

1 Answer 1

1

Check if it is not the first letter:

local prevent_single_letter = function (head)
    while head do
        if (head.id == GLYPH) then
          if head.prev then    --  !!!!!!!
            if unicode.utf8.match(unicode.utf8.char(head.char), "[aAàÀyY]") then 
                if ((head.prev.id == GLUE
[...]
3
  • Hello, thank you for your answer. However, I think the lua code does not work as expected (see my edit). Did I write the lua code correctly?
    – Bastien
    Commented Dec 12, 2021 at 9:23
  • @Bastien You added a dot after then, therefore you get a syntax error. Also you need to add an end matching the if. It should work after that. Commented Dec 12, 2021 at 10:15
  • I'm sorry, my mistake. It works well indeed, thank you!
    – Bastien
    Commented Dec 12, 2021 at 19:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .