Gregoriotex 与 fancyhdr 严重干扰,如何解决?

Gregoriotex 与 fancyhdr 严重干扰,如何解决?

这是这个问题. 但它解决的是不同的问题。

大约一年前,当上述问题被提出时,我还没有注意到。上周我偶然看到了它,因为它解决了fancyhdr,所以我试图看看它是什么。然而,我无法重建这个问题,也许是因为现在有了更新版本的gregoriotex

但是我发现了一个新问题,下面我会展示它。Gregoriotex当乐谱在分页符处处于活动状态时,会破坏多行页眉/页脚。而且不可能单独解决这个问题fancyhdr

下面是示例。它是 Gregorio 文档中一个示例的简化版本(http://gregorio-project.github.io/examples/O_Antiphons/O_Antiphons.zip

\documentclass[11pt]{article} % use larger type; default would be 10pt

\usepackage[autocompile]{gregoriotex}
\usepackage[latin]{babel}
\usepackage{fancyhdr}
\pagestyle{fancy}
\setlength{\headheight}{40pt}
\fancyhead[R]{%
  \parbox{0.4\textwidth}{This is a header with a hyphenated line of text in a parbox}
}

\def\move{\rule[-0.2em]{0.4pt}{1em}\,}

\gresethyphen{force}

\grechangedim{afterinitialshift}{2.2mm}{scalable}
\grechangedim{beforeinitialshift}{2.2mm}{scalable}

\grechangestyle{initial}{%
\fontsize{40}{40}\selectfont}%

\grechangestyle{annotation}{\scshape\bfseries\small}

\grechangestaffsize{15}

\begin{document}

\section*{Magnificat}
\vspace{1.5cm}\gresetinitiallines{0}
\gregorioscore{Magnificat}
\gresetinitiallines{1}\vspace{1.5cm}

\end{document}

Magnificat 乐谱Magnificat.gabc如下:

% !TEX encoding = UTF-8 Unicode
name: Magnificat;
gabc-copyright: (C) R. Padraic Springuel, This work is licensed under a Creative Commons Attribution 4.0 International License.;
office-part: Magnificat;
occasion: A Die 17 Ad Diem 23  Decembris;
transcriber: Br. Samuel Springuel, OSB;
transcription-date: 20131212;
mode: 2;
language: latin;
annotation: ii D;

%%

(f3) () <b><sp>V/</sp></b> Mag(e)ní(fe)fi(eh)cat(h.) á(h)ni(h)ma(h) me(h)<v>\move </v>a(g) Dó(e)mi(ef)num.(f.) (::Z)

<b><sp>V/</sp></b> Et(e) ex(fe)sul(eh)tá(h)vit(h) <v>\move </v>spí(hg)ri(hi)tus(i) me(hi)us(h.) (;)
in(h) De(h)o(h) sa(h)lu(h)tá(h)<v>\move </v>ri(g) me(ef)o.(f.) (::Z)

<b><sp>V/</sp></b> Qui(e)a(fe) re(eh)spé(h)xit(h) hu(h)mil(h)tá(h)tem(h) <v>\move </v>an(hg)cíl(hi)l<v>\ae</v>(i) su(hi)<v>\ae</v>:(h.) (;)
ec(h)ce(h) e(h)nim(h) ex(h) hoc(h) be(h)á(h)tam(h) me(h) di(h)cent(h) om(h)nes(h) ge(h)ne(h)ra(h)<v>\move </v>ti(g)ón(ef)es.(f.) (::Z)

<b><sp>V/</sp></b> Qui(e)a(fe) fe(eh)cit(h) mi(h)hi(h) <v>\move </v>mag(hg)na(hi) qui(i) po(hi)tens(h) est:(h.) (;)
et(h) sanc(h)tum(h) no(h)<v>\move </v>men(g) e(ef)jus.(f.) (::Z)

<b><sp>V/</sp></b> Et(e) mi(fe)se(eh)ri(h)cór(h)di(h)a(h) e(h)jus(h) a(h) pro(h)gé(h)ni(h)<v>\move </v>e(hg) in(hi) pro(i)gé(hi)ni(h)es(h.) (;)
ti(h)mén(h)ti(h)<v>\move </v>bus(g) e(ef)um.(f.) (::Z)

<b><sp>V/</sp></b> Fe(e)cit(fe) po(eh)tén(h)ti(h)am(h) in(h) <v>\move </v>brá(hg)chi(hi)o(i) su(hi)o:(h.) (;)
dis(h)pér(h)sit(h) su(h)pér(h)bos(h) men(h)te(h) cor(h)<v>\move </v>dis(g) su(ef)i.(f.) (::Z)

<b><sp>V/</sp></b> De(e)pó(fe)su(eh)it(h) po(h)<v>\move </v>tén(hg)tes(hi) de(i) se(hi)de,(h.) (;)
et(h) e(h)xal(h)tá(h)<v>\move </v>vit(g) hú(e)mil(ef)es.(f.) (::Z)

<b><sp>V/</sp></b> E(e)su(fe)ri(eh)én(h)tes(h) <v>\move </v>im(hg)plé(hi)vit(i) bo(hi)nis:(h.) (;)
et(h) dí(h)vi(h)tes(h) di(h)mí(h)sit(h) <v>\move </v>in(g)án(ef)es.(f.) (::Z)

<b><sp>V/</sp></b> Sus(e)cé(fe)pit(eh) Is(h)ra(h)el,(h) <v>\move </v>pú(hg)er(hi)um(i) su(hi)um,(h.) (;)
re(h)cor(h)dá(h)tus(h) mi(h)se(h)ri(h)cór(h)di(h)<v>\move\ae</v>(g) su(ef)<v>\ae</v>.(f.) (::Z)

<b><sp>V/</sp></b> Si(e)cut(fe) lo(eh)cú(h)tus(h) est(h) <v>\move </v>ad(hg) pa(hi)tres(i) nos(hi)tros,(h.) (;)
Ab(h)ra(h)ham,(h) et(h) sé(h)mi(h)ni(h) e(h)jus(h) <v>\move </v>in(g) s<v>\'\ae</v>(e)cu(ef)la.(f.) (::Z)

<b><sp>V/</sp></b> Gló(e)ri(fe)a(eh) <v>\move </v>Pa(hg)tri,(hi) et(i) Fí(hi)li(h)o,(h.) (;)
et(h) Spi(h)rí(h)tu(h)<v>\move </v>i(g) Sanc(ef)to.(f.) (::Z)

<b><sp>V/</sp></b> Si(e)cut(fe) er(eh)at(h) in(h) prin(h)ci(h)pí(h)o,(h) <v>\move </v>et(hg) nunc,(hi) et(i) sem(hi)per,(h.) (;)
et(h) in(h) s<v>\'\ae</v>(h)cu(h)la(h) s<v>\ae</v>(h)cu(h)ló(h)<v>\move </v>rum.(g) A(ef)men.(f.) (::e+)

当我运行此示例时,第一页的页眉(包含乐谱内的分页符)被截断。它只有第一行,而且没有连字符。

在此处输入图片描述

第二页,分页符位于乐谱之外,具有完整的页眉,并且带有连字符。

在此处输入图片描述

经过长时间的搜索,我找到了原因;这不是某些 TeX 参数的值不正确的问题,而是latex中的代码的问题gregotiotex。这意味着它不能轻易通过“fancyhdr”来解决。

问题代码位于gregoriotex.lua,其中安装了两个过滤器。当前版本中的第 751-752 行。

  luatexbase.add_to_callback('post_linebreak_filter', post_linebreak, 'gregoriotex.post_linebreak', 1)
  luatexbase.add_to_callback("hyphenate", disable_hyphenation, "gregoriotex.disable_hyphenation", 1)

这些过滤器在乐谱末尾被删除,但如果乐谱中出现分页符,它们在输出例程期间处于活动状态,因此在构建页眉和页脚期间也是如此fancyhdr。第一个过滤器在换行后会执行某些操作,我不确定具体是什么,但显然它会删除第一行以外的所有内容。第二个过滤器会禁止连字符。

由于这些过滤器是全局的,因此无法通过 轻松撤消fancyhdr。即使fancyhdr可以禁用它们,也必须在最后重新启用它们,因为它们不会在 TeX 组结束时恢复。

我已经尝试了几种方法来做到这一点,并想出了某种解决方案,需要和之间的合作gregoriotex。我将在答案中展示我的一种解决方案。但我想讨论其他选择。讨论之后,我可以将此作为问题fancyhdr提交给。gregoriotex

答案1

任何解决此问题的方法都应该涉及在排版受影响的页眉和页脚之前禁用这两个过滤器fancyhdr,然后将它们重置为最后的值。 因此,我定义了两个宏来执行此操作。 我没有关于分数是否有效的任何信息,因此我仅检查过滤器是否有效。 我必须保留该信息直到最后才能决定是否应该恢复它们。 我可以将一些布尔值放在 TeX 变量中,但我决定使用 luatex 构建命令以在测试期间恢复它们tex.print。 理想情况下,这些宏应该在内部定义gregoriotex。 一个问题是,在恢复时,所需的函数post_linebreakdisable_hyphenation是本地的gregoriotex.lua,所以我不能在外面使用它们。 我在 中添加了以下几行来gregoriotex.lua解决这个问题:

gregoriotex.post_linebreak               = post_linebreak
gregoriotex.disable_hyphenation          = disable_hyphenation

此宏禁用过滤器并记录恢复它们的代码:

\newcommand\gregoriodisable{\edef\filterrestore{\directlua{%
      local b
      b = luatexbase.in_callback('post_linebreak_filter', 'gregoriotex.post_linebreak')
      if b then 
        luatexbase.remove_from_callback('post_linebreak_filter', 'gregoriotex.post_linebreak')
        tex.print("luatexbase.add_to_callback('post_linebreak_filter', gregoriotex.post_linebreak, 'gregoriotex.post_linebreak', 1)")
      end
      b = luatexbase.in_callback('hyphenate', 'gregoriotex.disable_hyphenation')
      if b then 
        luatexbase.remove_from_callback('hyphenate', 'gregoriotex.disable_hyphenation')
        tex.print("luatexbase.add_to_callback('hyphenate', gregoriotex.disable_hyphenation, 'gregoriotex.disable_hyphenation', 1)")
      end
    }}}

它构建了一个\filterrestore包含 Lua 代码的命令,用于恢复现有的过滤器。这是用于恢复这些过滤器的 LaTeX 宏:

\newcommand\gregorioenable{\directlua{\filterrestore}}

然后我可以在受影响的标题中使用这些:

\fancyhead[R]{%
  \gregoriodisable
  \parbox{0.4\textwidth}{This is a header with a hyphenated line of text in a parbox}
  \gregorioenable
}

也许有更简单的方法,但至少这个是有效的。

以下是示例的完整代码:

\documentclass[11pt]{article}

\usepackage[autocompile]{gregoriotex}
\usepackage[latin]{babel}
\usepackage{xcolor}
\usepackage{fancyhdr}
\pagestyle{fancy}
\setlength{\headheight}{40pt}
\newcommand\filterrestore{}
\newcommand\gregoriodisable{\edef\filterrestore{\directlua{%
      local b
      b = luatexbase.in_callback('post_linebreak_filter', 'gregoriotex.post_linebreak')
      if b then 
        luatexbase.remove_from_callback('post_linebreak_filter', 'gregoriotex.post_linebreak')
        tex.print("luatexbase.add_to_callback('post_linebreak_filter', gregoriotex.post_linebreak, 'gregoriotex.post_linebreak', 1)")
      end
      b = luatexbase.in_callback('hyphenate', 'gregoriotex.disable_hyphenation')
      if b then 
        luatexbase.remove_from_callback('hyphenate', 'gregoriotex.disable_hyphenation')
        tex.print("luatexbase.add_to_callback('hyphenate', gregoriotex.disable_hyphenation, 'gregoriotex.disable_hyphenation', 1)")
      end
    }}}
\newcommand\gregorioenable{\directlua{\filterrestore}}

\fancyhead[R]{%
  \gregoriodisable
  \parbox{0.4\textwidth}{This is a header with a hyphenated line of text in a parbox}
  \gregorioenable
}

\def\move{\rule[-0.2em]{0.4pt}{1em}\,}

\gresethyphen{force}

\grechangedim{afterinitialshift}{2.2mm}{scalable}
\grechangedim{beforeinitialshift}{2.2mm}{scalable}

\grechangestyle{initial}{%
\fontsize{40}{40}\selectfont}%

\grechangestyle{annotation}{\scshape\bfseries\small}

\grechangestaffsize{15}

\begin{document}


\section*{Magnificat}
\vspace{1.5cm}\gresetinitiallines{0}
\gregorioscore{Magnificat}
\gresetinitiallines{1}\vspace{1.5cm}

\end{document}

必须将这些命令放在每个可能受影响的页眉/页脚中很烦人,因此在下一个版本中fancyhdr我将放置可以使用的钩子。

\AddToHook{fancyhdr/init}{\gregoriodisable}
\AddToHook{fancyhdr/exit}{\gregorioenable}

如果在 内完成此操作gregoriotex,那么这些钩子就可以添加到乐谱的开头,并在乐谱的结尾删除。这样\gregoriodisable就不需要里面的测试了,代码就可以大大简化。

由于问题不仅限于fancyhdr,还可能影响构建页眉和页脚的其他包,也可能影响shipout钩子或类似包中的代码atbegshi,我认为最好在输出例程之前和之后执行这些宏。不幸的是,没有钩子可以解决这个问题,即使有,一些类和包也会更改输出例程,它们也必须提供相同的钩子。我不知道最好的解决方案是什么。

相关内容