数学模式下的 lstinline 具有正确的字体大小

数学模式下的 lstinline 具有正确的字体大小

我经常排版有关计算机程序的数学公式(循环不变量等)。

我用打字机字体排版它们,在我的序言中说\lstset{basicstyle=\ttfamily}

我可以说

$\frac{\text{\lstinline£x£}}2$

但这很麻烦。我想输入

$\frac{\lstinline£x£}2$

因此,以类似的方式那个答案,我创建了一个数学模式版本\lstinline并使用它\ifmmode来选择适当的变体(请参阅末尾的 MWE):

\newcommand\lstinlinemm[1][]{%
   \hbox\bgroup % the \hbox is new
      \def\lst@boxpos{b}%
      \lsthk@PreSet\lstset{flexiblecolumns,#1}%
      \lsthk@TextStyle
      \lstinline@}

但是,在排版时(例如分数),这不能适当地缩放字体大小。

\hboxamstext\text@的数学模式版本)替换\text会导致代码在数学模式而不是文本模式下排版,并且我不清楚其中的原因。这是一个问题,因为它会导致\ttfamily与数学模式不可用相关的错误。

一个有趣的答案告诉我使用\mathchoice比我想象的要复杂,因为每个尺寸版本都是排版的,因为 TeX 事先不知道是否需要常规或 scriptsize 变体。

所以这意味着移动逐字的代码片段,据我所知这不是一件小事。

看起来 Lua 可以与 LuaTeX 的输入处理进行交互。这个答案引用process_input_buffer回调将逐字文本存储到 lua 变量中,然后使用它。但是,我理解它是逐行工作的,因此不适用于我的情况,因为我当然不想在公式中的 tex 源中换行。

答案中引用了 Paul Isambert 的文章还给出了一个使用回调的示例token_filter。我认为这也可以用来将代码片段吞噬到 lua 变量中,然后将其提供给\text。然而,token_filter 不复存在自 2016 年起。

MWE 如下:

\documentclass{standalone}
\usepackage{amsmath,listings}

\lstset{basicstyle=\ttfamily}

\makeatletter
\newcommand\lstinlinemm[1][]{%
   \hbox\bgroup
      \def\lst@boxpos{b}%
      \lsthk@PreSet\lstset{flexiblecolumns,#1}%
      \lsthk@TextStyle
      \lstinline@}
% On renomme le lstinline d'origine
\let\lstinlinetm\lstinline %%
% On met en place la sélection de la bonne version selon le mode actif
\DeclareRobustCommand\lstinline{\ifmmode\let\nextlstinline\lstinlinemm\else\let\nextlstinline\lstinlinetm\fi\nextlstinline}

\newcommand\£{\lstinline£} %£

\begin{document}
$\frac{\£x£}2$ $\frac{\text{\£x£}}2$
\end{document}

答案1

首先,请注意命令参数中的“逐字”通常不会“真正”起作用,即使有时看起来有效。

引用文档

5.1 参数内的列表

如果您想在参数中使用 \lstinline 或列表环境,则需要考虑一些事项。由于 TeX 在执行“lst- 宏”之前读取参数,因此此包无法执行任何操作来保存输入:空格缩小为一个空格,制表符和行尾转换为空格,TeX 的注释字符不可打印,等等。因此,您必须多做一些工作。您必须在以下四个字符前面分别加上反斜杠: \{}%。此外,如果 (i) 两个或多个空格彼此相连,或 (ii) 空格是行中的第一个字符,则必须以相同的方式保护空格。这还不够:每行都必须以“换行符”^^J 结束。并且您无法在这样的列表中退出到 LaTeX!

其次,如果您知道 TeX 内部的工作原理,您就会发现,为了使文本大小在最低级别的数学模式下正确,需要对每个数学模式执行内容 4 次。

无论哪种方式,在这种情况下您都需要一些深层的lstinline代码补丁。

代码lstinline相当复杂,理论上最好的修补方法是

  • 首先设置 catcode,
  • 然后收集参数,
  • 然后进行设置(例如包括\ttfamily在这种情况下)
  • 然后将所有内容排版。

我还没有弄清楚里面的代码是如何\lst@Init工作以分离 set-catcode 部分和 font-init 等部分的,所以我只是这样做。

输出

%! TEX program = lualatex
\documentclass{article}
\usepackage{amsmath}
\usepackage{listings}
\begin{document}

\makeatletter

\def\lstinline@#1{%
    %\lst@Init\relax  % originally this was included, we move it to later
    \lst@IfNextCharActive{\lst@InlineM#1}{\lst@InlineJ#1}% original definition, we don't handle M case
    %\lst@InlineJ#1%
}

\def\lst@InlineJ#1{%
    \def\lst@temp##1#1{%
        \text{%  ← this is added around
            \lst@Init\relax  % the init is moved to here
            \let\lst@arg\@empty \lst@InsideConvert{##1}%
            \lst@arg
            \lst@DeInit
        }%  ← we end up doing the init 4 times
        \egroup}%
    \lst@temp}

\makeatother

\lstset{basicstyle=\ttfamily}

Issue: this will disable the verbatim capturing mode e.g.
\lstinline+123    4 56+ does not preserve the double-space.

But otherwise it works.


\[
    \lstinline+123+\frac{\lstinline+123+^{\lstinline+123+_{\lstinline+123+}}}{2}
\]

\end{document}

答案2

@user202729 的解决方案符合我的需要,但有两处修改:

  • 我只会在数学模式下使用它,\lstinline在文本模式下保留原来的
  • 为了使%正常\工作并允许不平衡的{结束},我将它们的 catcode 设置为 12。我们可以通过将 的 catcode也设置为 12 来避免连续空间的崩溃。然而,我并不知道这会带来什么意外的副作用。据推测这可能会干扰对listings这些字符的处理,但就我而言,我无论如何都不想让它对它们做任何事情,所以……

我也没有尝试去处理\lstinline{code},在我看来这是没用的。

\newcommand\lstinlinemm[1][]{%
   \bgroup
      \def\lst@boxpos{b}%
      \lsthk@PreSet\lstset{flexiblecolumns,#1}%
      \lsthk@TextStyle
      \lstinline@math}
      
\def\lstinline@math#1{%
    \begingroup
    \catcode`\%=12
    \catcode`\{=12
    \catcode`\}=12
    \catcode`\\=12
    \def\lst@temp##1#1{%
        \text{%  ← this is added around
            \lst@Init\relax  % the init is moved to here
            \let\lst@arg\@empty \lst@InsideConvert{##1}%
            \lst@arg
            \lst@DeInit
        }%  ← we end up doing the init 4 times
        \endgroup\egroup}%
    \lst@temp}
    
% On renomme le lstinline d'origine
\let\lstinlinetm\lstinline %%
% On met en place la sélection de la bonne version selon le mode actif
\DeclareRobustCommand\lstinline{\ifmmode\let\nextlstinline\lstinlinemm\else\let\nextlstinline\lstinlinetm\fi\nextlstinline}

相关内容