在格式化带有子项的双列索引时,我遇到两个问题:
\documentclass{scrartcl}
\usepackage{imakeidx}
\usepackage[indentunit=15pt,justific=raggedright, columnsep=10pt, font=footnotesize]{idxlayout}
\makeindex
\begin{document}
Some text.
\index{Donahue!Alice}
\index{Donahue!Barney}
\index{Jones!Alvin}
\index{Jones!Billy}
\index{Jones!Carter}
\index{Jones!Dennis}
\index{Smith!Alex}
\index{Smith!Brian}
\index{Smith!Carrie}
\index{Smith!Dewey}
\index{Smith!Eric}
\index{Smith!Frank}
\index{Smith!Gary}
\index{Smith!Huey}
\index{Smith!Irma}
\index{Smith!Joey}
\index{Smith!Kevin}
\index{Scullion!Alex}
\index{Scullion!Brian}
\index{Scullion!Carrie}
\index{White!Alice}
\index{White!Barney}
\idxlayout{columns=2, font=small, columnsep=20pt}
\printindex
\end{document}
在此 MWE 中,(1) 索引条目 »Smith« 与其子条目分离,并且 (2) 组 (条目 + 子条目) 之间的空间不均匀。
我有两个问题:是否有可能(1)修复项目组之间的空间,以及(2)实现一种算法,使条目与同一列中至少一个(或两个或三个)子条目粘在一起?
对于 MWE,这会导致右列比左列短一点。»Alex, 1« 将被拉向 »Smith«。在我看来,这比现在的情况要好一点。
答案1
您可以重新定义\@idxitem
(让其\item
等于里面的theindex
)来做一些簿记,即重置一个计数器,使后续每个计数器\subitem
都会减少。
\subitem
当计数器的值为正时还会增加惩罚,因此禁止分页/分列。
\documentclass{scrartcl}
\usepackage{imakeidx}
\usepackage[indentunit=15pt,justific=raggedright, columnsep=10pt, font=footnotesize]{idxlayout}
\makeindex
\makeatletter
\let\ori@idxitem\@idxitem
\def\@idxitem{\clear@penalties\ori@idxitem}
\def\clear@penalties{\subitem@count=3 }
\newcount\subitem@count
\def\subitem{%
\advance\subitem@count -1
\par
\ifnum\subitem@count>0 \penalty10000 \fi
\ori@idxitem\hspace*{\ila@subindent}%
}
\makeatother
\begin{document}
Some text.
\index{Donahue!Alice}
\index{Donahue!Barney}
\index{Jones!Alvin}
\index{Jones!Billy}
\index{Jones!Carter}
\index{Jones!Dennis}
\index{Smith!Alex}
\index{Smith!Brian}
\index{Smith!Carrie}
\index{Smith!Dewey}
\index{Smith!Eric}
\index{Smith!Frank}
\index{Smith!Gary}
\index{Smith!Huey}
\index{Smith!Irma}
\index{Smith!Joey}
\index{Smith!Kevin}
\index{Scullion!Alex}
\index{Scullion!Brian}
\index{Scullion!Carrie}
\index{White!Alice}
\index{White!Barney}
\idxlayout{columns=2, font=small, columnsep=20pt}
\printindex
\end{document}
这将使两个子项与主条目保持在一起。使用
\def\clear@penalties{\subitem@count=2 }
您只会获得一个附加的子项目。
答案2
垂直间距不同,因为只有当有新字母时才会插入空格(根据此文档)。既然你不喜欢,我无论如何都要修复它。
我尝试用 LaTeX3 写解决方案,但不知何故正则表达式在布尔表达式中不起作用。为了方便,我改用 Lua。也就是说,下面的代码只能在 LuaLaTeX 中运行。想法很简单:读取ind
生成的文件makeindex
并根据我们的目的对其进行微调。
您可能需要编译该文档两次才能使其正常工作。
\documentclass{scrartcl}
\usepackage{imakeidx}
\usepackage[indentunit=15pt,justific=raggedright, columnsep=10pt, font=footnotesize]{idxlayout}
\usepackage{etoolbox}
\usepackage{luacode}
\usepackage{expl3}
\usepackage{hyperref}
\makeindex
\begin{luacode*}
local inspect = require"inspect"
function fine_tune_index()
local index_filename = tex.jobname .. ".ind"
local newindex_filename = tex.jobname .. "-new.ind"
local attr = lfs.attributes(index_filename)
if attr == nil then
return
end
local index_lines = {}
for line in io.lines(index_filename) do
table.insert(index_lines, line)
end
local new_lines = {}
local new_line_buffer = {}
local line=nil
local has_space=true
local search_end = #index_lines - 1
local item_count = 0
function flush_line_buffer()
if #new_line_buffer > 1 then
table.insert(new_line_buffer, 1, [[\begin{minipage}{\linewidth}]])
table.insert(new_line_buffer, 4, [[\end{minipage}]])
end
for _, item in ipairs(new_line_buffer) do
table.insert(new_lines, item)
end
new_line_buffer = {}
end
for i=2,search_end do
line = index_lines[i]
if line:find("\\item") then
item_count = item_count + 1
flush_line_buffer()
if not has_space then
table.insert(new_lines, "\\indexspace")
end
has_space = false
table.insert(new_line_buffer, line)
elseif line:find("\\indexspace") then
has_space=true
flush_line_buffer()
table.insert(new_lines, line)
else
table.insert(new_line_buffer, line)
end
end
flush_line_buffer()
table.insert(new_lines, 1, index_lines[1])
table.insert(new_lines, index_lines[#index_lines])
local out_text = table.concat(new_lines, "\n")
local outfile = io.open(newindex_filename, "w")
outfile:write(out_text)
outfile:close()
end
\end{luacode*}
\AtEndDocument{
\directlua{fine_tune_index()}
}
\begin{document}
Some text.
\index{Donahue!Alice}
\index{Donahue!Barney}
\index{Jones!Alvin}
\index{Jones!Billy}
\index{Jones!Carter}
\index{Jones!Dennis}
\index{Smith!Alex}
\index{Smith!Brian}
\index{Smith!Carrie}
\index{Smith!Dewey}
\index{Smith!Eric}
\index{Smith!Frank}
\index{Smith!Gary}
\index{Smith!Huey}
\index{Smith!Irma}
\index{Smith!Joey}
\index{Smith!Kevin}
\index{Scullion!Alex}
\index{Scullion!Brian}
\index{Scullion!Carrie}
\index{White!Alice}
\index{White!Barney}
\idxlayout{columns=2, font=small, columnsep=20pt}
\ExplSyntaxOn
% create a new int variable to bypass checks
\int_new:c {\jobname-new@idxfile}
\ExplSyntaxOff
\printindex[\jobname-new]
\end{document}
答案3
好的,这是一个 LaTeX 解决方案。
不幸的是,该idxlayout
软件包没有提供很多钩子来进行这种修改,所以我的更改有些侵入性,如果您使用不同的布局选项,更改就会中断。
如果您遇到问题,以下内容可以变得更通用一些。
您应该将此代码放入序言中,例如在加载之后idxlayout
。它的作用是重新定义所需的内部结构以idxlayout
进行所需的更改。我试图尽可能地减少侵入性,但效果不佳。
% Could put this into a separate package which loads idxlayout
\makeatletter
% no additional space before new letters
\let\indexspace\relax
% rescue original definition
\let\orig@idxitem\@idxitem
% we need to know if a subitem is the first after an item
\newif\ifafteritem
% \item should do what it originally does, plus add vertical space,
% plus set the flag for \subitem
\renewcommand{\@idxitem}{%
\orig@idxitem
\vspace{\ila@initsep}%
\afteritemtrue
}
% \subitem should refer to original definition of \@idxitem (to avoid
% adding vertical space), plus add penalty if it's the first subitem.
\renewcommand{\subitem}{%
\orig@idxitem
\ifafteritem\nobreak\fi
\hspace*{\ila@subindent}%
\afteritemfalse
}%
\renewcommand{\subsubitem}{\orig@idxitem\hspace*{\ila@subsubindent}}%
\makeatother
结果: