我正在研究此 Stack Exchange 线程中提供的解决方案:有没有办法自动粉碎所有内联数学(但仅限于垂直方向)?,最初由用户 Mico 回答。我在下面附上了 Mico 回答的相关代码。此代码将 \smash 应用于 $$(内联数学)环境中的所有内容。但是,我有兴趣扩展此功能,以便不仅将 \smash 应用于数学,还将 \smash 应用于正文中带有降序的任何字母,例如“p”、“q”、“y”等。
正如我与 Mico 讨论的那样,实现这一附加功能似乎比最初预期的更具挑战性。如果您有任何建议或替代方法来实现预期效果,我将不胜感激您的帮助。感谢您的帮助!
% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{amsmath} % for '\dfrac' macro
\usepackage{lipsum} % filler text
\usepackage{luacode} % for 'luacode' env.
\begin{luacode}
function smash ( s )
return ( s:gsub ( "%b$$" , "\\smash{%1}" ) )
end
\end{luacode}
\newcommand\SmashOn{\directlua{luatexbase.add_to_callback (
"process_input_buffer", smash, "smash" )}}
\newcommand\SmashOff{\directlua{luatexbase.remove_from_callback (
"process_input_buffer", "smash" )}}
\begin{document}
\hrule % draw line to illustrate width of textblock
\lipsum[1][1-5] $\dfrac{\dfrac{v}{v}}{\dfrac{w}{x}}$ \lipsum[1][5-8]
\hrule
\SmashOn % activate the Lua function
\lipsum[1][1-5] $\dfrac{\dfrac{v}{v}}{\dfrac{w}{x}}$ \lipsum[1][5-8]
\hrule
\SmashOff % deactivate the Lua function
\lipsum[1][1-5] $\dfrac{\dfrac{v}{v}}{\dfrac{w}{x}}$ \lipsum[1][5-8]
\hrule
\end{document}
答案1
在我看来,这似乎是一个非常糟糕的主意——通常你希望下降部分有深度,这样它们就不会与其他字符发生碰撞。然而,它不是也使用 Lua 自动执行此操作比较棘手:
\documentclass{standalone}
%% The next section contains the code that is necessary to automatically smash
%% descenders in math and text modes.
%%% BEGIN REQUIRED CODE %%%
\newif\ifautosmash
\usepackage{luacode}
\begin{luacode*}
local iftrue = token.create("iftrue").mode
-- Handle descenders in text mode
local function smash_nodes(head)
-- Check to see if autosmashing is enabled
if token.create("ifautosmash").mode ~= iftrue then
return head
end
-- Iterate over all nodes in the list
local n = head
repeat
-- Remove descenders
if n.id == node.id("glyph") then
local new = node.copy_list(n, n.next)
-- We can't modify the depth of a glyph directly, so we
-- need to pack it into a box.
local box = node.hpack(new)
box.depth = 0
-- Replace the glyph
head, box = node.insert_after(head, n, box)
head = node.remove(head, n)
n = node.free(n)
end
n = n.next
until not n
return head
end
luatexbase.add_to_callback("pre_linebreak_filter", smash_nodes, "smash_nodes")
luatexbase.add_to_callback("hpack_filter", smash_nodes, "smash_nodes")
-- Handle descenders in math mode
local function smash_math(...)
local n = node.mlist_to_hlist(...)
if token.create("ifautosmash").mode == iftrue then
n = node.hpack(n)
n.depth = 0
end
return n
end
luatexbase.add_to_callback("mlist_to_hlist", smash_math, "smash_math")
\end{luacode*}
%%% END REQUIRED CODE %%%
%% The following code is just to draw a box around its contents; it is
%% *not* necessary for the rest of the code to work.
%%% BEGIN EXTRA CODE %%%
\renewcommand{\arraystretch}{1.75}
\ExplSyntaxOn
\dim_const:Nn \c__max_thickness_dim { 0.1pt }
\dim_new:N \g__max_half_ex_dim
\dim_new:N \l__max_asc_ht_dim
\dim_new:N \l__max_des_dp_dim
\box_new:N \l__max_contents_box
\box_new:N \l__max_hline_box
\box_new:N \l__max_vline_box
\cs_new:Nn \__max_font_size: {
\fontsize { 0.2em } { 0.2em } \selectfont \scshape
}
\cs_new:Nn \__max_hline:nn {
\box_move_up:nn { #2 - \g__max_half_ex_dim } {
\hbox_overlap_left:n {
\__max_font_size: #1
\skip_horizontal:n {
\g__max_half_ex_dim + (\c__max_thickness_dim / 2)
}
}
}
\box_move_up:nn { #2 } { \box_use:N \l__max_hline_box }
\box_move_up:nn { #2 - \g__max_half_ex_dim } {
\hbox_overlap_right:n {
\skip_horizontal:n {
\box_wd:N \l__max_contents_box +
\g__max_half_ex_dim +
(\c__max_thickness_dim / 2)
}
\__max_font_size: #1
}
}
}
\cs_new:Nn \__max_vline:n {
\hbox_set_to_wd:Nnn \l_tmpa_box { 0pt } { \hss \__max_font_size: #1 \hss }
\box_move_down:nn {
\box_dp:N \l__max_contents_box +
\box_ht:N \l_tmpa_box +
\g__max_half_ex_dim +
(\c__max_thickness_dim / 2)
} {
\box_use:N \l_tmpa_box
}
\box_move_up:nn {
\box_ht:N \l__max_contents_box +
\box_dp:N \l_tmpa_box +
\g__max_half_ex_dim +
(\c__max_thickness_dim / 2)
} {
\box_use_drop:N \l_tmpa_box
}
\box_use:N \l__max_vline_box
}
\prg_new_conditional:Nnn \__max_dimcomp:nn { T } {
\bool_if:nTF {
\dim_compare_p:n {
#1 < 0.8 #2
}
||
\dim_compare_p:n {
#1 > 1.2 #2
}
} {
\prg_return_true:
} {
\prg_return_false:
}
}
\NewDocumentCommand { \drawbox } { m } {
\group_begin:
\__max_font_size:
\dim_gset:Nn \g__max_half_ex_dim { 0.5ex }
\group_end:
\hbox_set:Nn \l__max_contents_box { \color_ensure_current: #1 }
\hbox_set_to_wd:Nnn \l__max_hline_box { 0pt } {
\vrule
width \box_wd:N \l__max_contents_box height \c__max_thickness_dim
height 0.5 \c__max_thickness_dim
depth 0.5 \c__max_thickness_dim
\hss
}
\hbox_set_to_wd:Nnn \l__max_vline_box { 0pt } {
\hss
\vrule
width \c__max_thickness_dim
height \dim_eval:n {
\box_ht:N \l__max_contents_box + (\c__max_thickness_dim / 2)
}
depth \dim_eval:n {
\box_dp:N \l__max_contents_box + (\c__max_thickness_dim / 2)
}
\hss
}
\hbox_set:Nn \l_tmpa_box { l h t i }
\dim_set:Nn \l__max_asc_ht_dim { \box_ht:N \l_tmpa_box }
\hbox_set:Nn \l_tmpa_box { y j p g }
\dim_set:Nn \l__max_des_dp_dim { \box_dp:N \l_tmpa_box }
\hbox:n {
\color_group_begin:
\color_select:n { red ! 50 ! black ! 75 ! white }
\__max_hline:nn { bl } { 0pt }
\__max_hline:nn { ht } { \box_ht:N \l__max_contents_box }
\__max_hline:nn { ex } { 1ex }
\__max_hline:nn {
\__max_dimcomp:nnT {
0pt
} {
\box_dp:N \l__max_contents_box
} {
dp
}
} { - \box_dp:N \l__max_contents_box }
\__max_hline:nn {
\__max_dimcomp:nnT {
\l__max_asc_ht_dim
} {
\box_ht:N \l__max_contents_box
} {
asc
}
} { \l__max_asc_ht_dim }
\__max_hline:nn {
\__max_dimcomp:nnT {
\l__max_des_dp_dim
} {
\box_dp:N \l__max_contents_box
} {
des
}
} { -\l__max_des_dp_dim }
\__max_vline:n { l }
\hbox_overlap_right:n {
\skip_horizontal:n { \box_wd:N \l__max_contents_box }
\__max_vline:n { r }
}
\color_group_end:
\box_use_drop:N \l__max_contents_box
}
}
\ExplSyntaxOff
%%% END EXTRA CODE %%%
%% Example usage and demonstration
\begin{document}
\begin{tabular}{rl}
\autosmashfalse \drawbox{glyph glyph glyph} &
\autosmashtrue \drawbox{glyph glyph glyph} \\
\autosmashfalse \drawbox{glyph $\displaystyle\int$ glyph} &
\autosmashtrue \drawbox{glyph $\displaystyle\int$ glyph} \\
\autosmashfalse \drawbox{glyph $\sqrt{x}^2$ glyph} &
\autosmashtrue \drawbox{glyph $\sqrt{x}^2$ glyph} \\
\autosmashfalse \drawbox{glyph $q_{g_{y_{p_j}}}$ glyph} &
\autosmashtrue \drawbox{glyph $q_{g_{y_{p_j}}}$ glyph} \\
\multicolumn{2}{p{2.3in}}{
\fontsize{8pt}{0pt}\selectfont \autosmashtrue
The image on top displays how the descenders are automatically
smashed when \texttt{\char`\\ auto\-smash\-true} is running.
Collisions are quite frequent, so be very careful with low-hanging
equations like $\sqrt{x_1} = \int_0^1 \beta_y$. Notice that only the
depth is tighter---the line above is lowered by \LaTeX{} to account
for its extra height.
}
\end{tabular}
\end{document}
您可以在比较表中看到,只要您打开 ,深度就会被完全移除\autosmashtrue
,而不会影响高度、宽度或定位。这在表格中看起来还不错,但在下面的正文演示中看起来很糟糕。
答案2
您不需要修改单个降部字形框以避免它们影响行距,该功能已内置于经典 TeX 中。
\documentclass{article}
\usepackage{amsmath} % for '\dfrac' macro
\usepackage{lipsum} % filler text
\def\SmashOn{\par\lineskiplimit=-\maxdimen}
\def\SmashOff{\par\lineskiplimit= \normallineskiplimit}
\begin{document}
\hrule % draw line to illustrate width of textblock
\lipsum[1][1-5] $\dfrac{\dfrac{v}{v}}{\dfrac{w}{x}}$ \lipsum[1][5-8]
\hrule
\SmashOn % activate the Lua function
\lipsum[1][1-5] $\dfrac{\dfrac{v}{v}}{\dfrac{w}{x}}$ \lipsum[1][5-8]
\hrule
\SmashOff % deactivate the Lua function
\lipsum[1][1-5] $\dfrac{\dfrac{v}{v}}{\dfrac{w}{x}}$ \lipsum[1][5-8]
\hrule
\end{document}