1

I am using imakeidx. How do I group entries in the (person) index in a way that they do not get split across page boundaries? My goal here is to have groups of surnames "Smith" and a group of "Jones", plus 1-12 first names each, in the index, and keep those groups on the same page.

I have the feeling that some application of \nopagebreak might solve it, but where?

Here is a pdflatex MWE and below an image of the output, with a big red rectangle as annotation to show where the surname in index gets separated from the several first names. All the "Wilson" names should be on same page.

The MWE is pdflatex file:

\documentclass{article} \usepackage{imakeidx} \makeindex[name=person, title={Index},options=-s example.ist, columns=1] % Use .ist for dotfill \makeindex \begin{document} Page1 \index[person]{{Smith}!{John1 , something}} \index[person]{{Smith}!{John2 , something}} \index[person]{{Smith}!{John3 , something}} \index[person]{{Johnson}!{John1 , something}} \index[person]{{Johnson}!{John2 , something}} \index[person]{{Johnson}!{John3 , something}} \index[person]{{Williams}!{John1 , something}} \index[person]{{Williams}!{John2 , something}} \index[person]{{Williams}!{John3 , something}} \index[person]{{Brown}!{John1 , something}} \index[person]{{Brown}!{John2 , something}} \index[person]{{Brown}!{John3 , something}} \index[person]{{Jones}!{John1 , something}} \index[person]{{Jones}!{John2 , something}} \index[person]{{Jones}!{John3 , something}} \index[person]{{Miller}!{John1 , something}} \index[person]{{Miller}!{John2 , something}} \index[person]{{Miller}!{John3 , something}} \index[person]{{Davis}!{John1 , something}} \index[person]{{Davis}!{John2 , something}} \index[person]{{Davis}!{John3 , something}} \index[person]{{Wilson}!{John1 , something}} \index[person]{{Wilson}!{John2 , something}} \index[person]{{Wilson}!{John3 , something}} \index[person]{{Taylor}!{John1 , something}} \index[person]{{Taylor}!{John2 , something}} \index[person]{{Taylor}!{John3 , something}} \index[person]{{Martinez}!{John1 , something}} \index[person]{{Martinez}!{John2 , something}} \index[person]{{Martinez}!{John3 , something}} \index[person]{{Thompson}!{John1 , something}} \index[person]{{Thompson}!{John2 , something}} %\index[person]{{Thompson}!{John3 , something}} \index[person]{{Lee}!{John1 , something}} \index[person]{{Lee}!{John2 , something}} \index[person]{{Lee}!{John3 , something}} \printindex[person] \end{document} 

which uses the one line style example.ist

delim_1 "\\nobreak\\dotfill " 

to achieve the nice dot fill. All Wilson's should be on the same page pls

All surnames and first names grouped nicely, good. However, the name "Wilson" (and its three first names) is split across two pages. How do I that?

I tried in the .ist style to add \nopagebreak but nothing has the desired effect. For example

% group_skip "\n\n \\nopagebreak\\indexspace\n" % item_1 "\\par\\nopagebreak" % item_0 "\\nopagebreak" % prefix "\\par\\nopagebreak" % delim_1 "\\nobreak\\nopagebreak\\dotfill " % delim_1 "\\nobreak\\par\\nopagebreak\\dotfill " % delim_1 "\\nopagebreak\\dotfill " % delim_1 "\\nolinebreak\\dotfill " 

How to massage the .ist style to keep the groups of surnames plus 1-12 first names on the same page? In this case, I would expect an extra empty line of page 2 and "Wilson" plus 3 first names on page as a group.

PS: While I look at the initial comments, I realize that the example above concentrates on 1-12 sub-items (first names), the full latex file has a few instances with almost 100 sub-items (first names) spanning more than a page which leads to additional challenges. Ideally, a solution would handle the whole range.

Just a wild guess, but if we choose a threshold N and can have all groups of N together and split larger ones, would that work? Maybe something simple like

if there are less than N==5 sub-items/names then keep them together else do nothing and break as usual 

might work? But how to code that?

PS2: Thank you for all your help so far. In the first answer, a solution is suggested that works it seems, but not for wrapped lines in index. Am adding here a second MWE to demonstrate and a second image to visualize the issue.

\documentclass{article} \usepackage{imakeidx} % ---- \makeatletter \newcommand{\nobreakafteritem}{} \newcommand{\setnobreakafteritem}{\renewcommand{\nobreakafteritem}{\par\penalty10000\relax \renewcommand{\nobreakafteritem}{}}} \usepackage{etoolbox}\pretocmd\subitem{\nobreakafteritem}{}{\fail} \usepackage{etoolbox}\pretocmd\@idxitem{\setnobreakafteritem}{}{\fail} \makeatother %---------------- \makeindex[name=person, title={Index},options=-s example.ist, columns=1] % Use .ist for dotfill \makeindex \begin{document} Page1 \index[person]{{Smith}!{John1 , something}} \index[person]{{Smith}!{John2 , something}} \index[person]{{Smith}!{John3 , something}} \index[person]{{Johnson}!{John1 , something}} \index[person]{{Johnson}!{John2 , something}} \index[person]{{Johnson}!{John3 , something}} \index[person]{{Williams}!{John1 , something}} \index[person]{{Williams}!{John2 , something}} %\index[person]{{Williams}!{John3 , something}} %ORG \index[person]{{Williams}!{John3 , something very long wrap the line extra long and longer and longer and longer}} \index[person]{{Brown}!{John1 , something}} \index[person]{{Brown}!{John2 , something}} \index[person]{{Brown}!{John3 , something}} \index[person]{{Jones}!{John1 , something}} \index[person]{{Jones}!{John2 , something}} \index[person]{{Jones}!{John3 , something}} \index[person]{{Miller}!{John1 , something}} \index[person]{{Miller}!{John2 , something}} \index[person]{{Miller}!{John3 , something}} \index[person]{{Davis}!{John1 , something}} \index[person]{{Davis}!{John2 , something}} \index[person]{{Davis}!{John3 , something}} \index[person]{{Wilson}!{John1 , something}} \index[person]{{Wilson}!{John2 , something}} %\index[person]{{Wilson}!{John3 , something}} \index[person]{{Taylor}!{John1 , something}} \index[person]{{Taylor}!{John2 , something}} \index[person]{{Taylor}!{John3 , something}} \index[person]{{Martinez}!{John1 , something}} \index[person]{{Martinez}!{John2 , something}} \index[person]{{Martinez}!{John3 , something}} \index[person]{{Thompson}!{John1 , something}} \index[person]{{Thompson}!{John2 , something}} \index[person]{{Thompson}!{John3 , something}} % \index[person]{{Lee}!{John1 , something}} \index[person]{{Lee}!{John2 , something}} \index[person]{{Lee}!{John3 , something}} \printindex[person] \end{document} 

for the PS2, an example of a wrapped line in index that splits over 2 pages

4
  • \usepackage{etoolbox}\pretocmd\subitem{\par\nobreak}{}{\fail} could work. Commented Apr 19, 2021 at 20:49
  • Firstly, that solves this example. Thanks! That encouraged me to try a few more variants. In doing that, this solution seems to have unexpected effects when the number of first names is very large, like more than the number of lines on a page. Therefore, secondly, would you know how to generalize this when we have not only between 1 and a dozen or so but, e.g., between 1 and 100 first names per surname? And 100 just chosen as a number larger than the number of lines in the index page. Commented Apr 19, 2021 at 21:41
  • Looking at tex.stackexchange.com/questions/21983/… I tried this \usepackage{etoolbox}\pretocmd\subitem{\par\widowpenalty 10000\raggedbottom}{}{\fail} but I do not know how to set the penalties such that groups of 1 to 10 stay to together and larger groups can be broken up. Commented Apr 19, 2021 at 22:09
  • well if you have many subitems and want to break between them it will get a bit more complicated. Commented Apr 19, 2021 at 22:12

2 Answers 2

0

A completely untested possibility:

\makeatletter \newcommand{\nobreakafteritem}{} \newcommand{\setnobreakafteritem}{\renewcommand{\nobreakafteritem}{\par\penalty10000\relax \renewcommand{\nobreakafteritem}{}}} \pretocmd\subitem{\nobreakafteritem}{}{\fail} \pretocmd\@idxitem{\setnobreakafteritem}{}{\fail} \makeatother 

The basic idea: After an \item in the index (which is generated by \@idxitem), define \nobreakafteritem to put a no break penalty, but then after its first invocation, it reverts to a no-op. Then patch \subitem to call \nobreakafteritem. It would be possible to have \nobreakafteritem self-destruct after a set number of invocations, or perhaps even lower the penalty with each invocation until it goes down to zero.

8
  • Sounds intriguing. When I tried this as-is today, there is an error Runaway argument? {\renewcomand {\nobreakafteritem }{\par \penalty 10000\relax \renewcomand \ETC. ! File ended while scanning use of \@argdef. <inserted text> \par <*> index_example.tex Seems like a bracket is missing? My best guesses where not able to get this to work probably. Therefore, can you help please to make this code snippet run properly for testing ? Thanks. PS: Don't we need a \usepackage{etoolbox} before the pretocmd ? Commented Apr 20, 2021 at 13:26
  • Ok,I managed to get this working with three edits (1) "renewcomand" is misspelled and needs an extra 'm' (2) added an extra curly bracket after "renewcomand{\nobreakafteritem}{} } }" (Q: Was that the correct fix?) and (3) use the 'etoolbox'. Commented Apr 20, 2021 at 15:12
  • While that solves the grouping of surnames plus first names the MWE (thanks!), there are two issue with this approach (1) it destroy the right alignment of the '....1' (see original picture for expected output). All the page numbers "1" are not in the same right column any more. And (2) change the MWE line \index[person]{{Williams}!{John3 , something very long wrap the line extra long and longer and longer and longer}} to see that such a wrapped, long index line (if it is the last one at the bottom of page) is NOT grouped correctly. Commented Apr 20, 2021 at 15:12
  • Thoughts on how to proceed? Commented Apr 20, 2021 at 15:14
  • @Hans I'll take a look later today. Commented Apr 20, 2021 at 15:45
0

Add item_01 "\\nopagebreak\n \\subitem " to your .ist file to insert a \nopagebreak between items on level 0 (main) and level 1 (sub).

Add item_1 "\\nopagebreak\n \\subitem " to your .ist file to insert a \nopagebreak between items on level 1 (sub) and level 1 (sub).

Add item_x1 "\\nopagebreak\n \\subitem " to your .ist file to insert a \nopagebreak between items on level 0 (main) without associated page numbers and level 1 (sub).

The "\n \\subitem " is what is inserted by default in these places, so what the above does is purely inserting \\nopagebreak before starting the next subitem.

Here is a list of the keys (like item_01) you can use in the .ist file.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.