latex3 / latex2e

The LaTeX2e kernel
https://www.latex-project.org/
LaTeX Project Public License v1.3c
1.88k stars 261 forks source link

`multicol`: allow column rules to be customized #698

Closed RuixiZhang42 closed 1 year ago

RuixiZhang42 commented 2 years ago

Brief outline of the enhancement

To govern the depth of rules between columns, multicol does two things:

  1. A hard-coded \rlap{\phantom p};
  2. Maintain the largest depth in \dimen\tw@ while typesetting the columns.

The net effect is that the rules will be as deep as the descender of the letter “p”, or deeper (if there are any deeper columns). These design decisions make sense for Latin-based languages. They do not make sense for languages that lack the concept of a “Latin descender”.

The pictures below contain language that must be typeset with external packages (e.g., fontspec, xeCJK). Because of \RequirePackage{latexbug}, a minimal code example cannot be provided. However, there is some code to test at the end of this issue.

A more detailed and concrete example

There is no descender in Chinese/Japanese/Korean. The text area is typically measured based on the ideographic em-box. The picture below shows my attempt to emulate typesetting dictionary entries in traditional Chinese. The green band shows the height and depth of the ideographic em-box. The column rules extend below the ideographic em-box. Not a single “p” is present, which makes the rules out of place. (BTW, the dictionary entries shown here are for “letter/symbol/character”, “canon/law/standard work of scholarship”, and “to learn”.)

lastlinep

The desired effect is for the rules to align with the ideographic em-box:

lastlineembox

What can be done

  1. Allow users to replace the default “p”.
    
    % So instead of
    \setbox\z@\hbox{p}\global\dimen\tw@\dp\z@
    ...
    \rlap{\phantom p}%

% Use `customized letters and/or symbols' \setbox\z@\hbox{<customized letters and/or symbols>}\global\dimen\tw@\dp\z@ ... \rlap{\phantom{<customized letters and/or symbols>}}% extra braces needed!

2. When typesetting the rules, allow users to overwrite the depth.
```latex
% So instead of
       \hss{\columnseprulecolor\vrule
              \@width\columnseprule}\hss

% Support `depth overwrite'
       \hss{\columnseprulecolor\vrule
              \@width\columnseprule<depth overwrite with `\@depth...'>}\hss

To produce the second picture above, I exploited/abused the fact that \vrule\@width\columnseprule was preceded by \columnseprulecolor. So I can say

% Sneaky hack:
\renewcommand*\columnseprulecolor[3]{\normalcolor#1#2#3depth0.12em}

Code to test

\documentclass{article}

\usepackage{color,lipsum}

\usepackage{multicol}
\setlength\columnseprule{0.5pt}

\makeatletter
% We add \lastlinebackground before typesetting the left-to-right columns
\def\mc@align@columns{\lastlinebackground\LR@column@boxes}%
% Let us add background color to the last line
\newcommand*\lastlinebackground{%
  \rlap{%
% Assume that the ideographic em-box is 0.88em high and 0.12em deep
    \vrule\@width\z@\@height0.88em\@depth0.12em
% A full-width rule spanning the entire last line
    {\color{green}\vrule\@width\full@width}%
  }%
}%
\makeatother

\begin{document}

\begin{multicols}{3}
\lipsum
\end{multicols}

% Very sneaky hack follows:
\renewcommand*\columnseprulecolor[3]{\normalcolor#1#2#3depth0.12em}%

\begin{multicols}{3}
\lipsum
\end{multicols}

\end{document}
FrankMittelbach commented 2 years ago

3rd option: use \usepackage{multicolrule} have you ever looked at that? I'm a bit reluctant to extend the interface here in a fairly minor and nonextensible way, if there is a general (and I think) nice way to get much better results --- and your problem should be fixed with that too.

RuixiZhang42 commented 2 years ago

@FrankMittelbach Thank you for pointing to multicolrule. I took a quick look at the code of that package and these are my thoughts:

… if there is a general (and I think) nice way to get much better results --- and your problem should be fixed with that too.

Many things are already hard-coded in multicol, for example, the calculations that involve putting rigid column boxes at the correct position against the background grid (basically the grid appearance is faked, but with rigor and care). With multicolrule, however, there is no such guarantee (see https://github.com/polysyllabic/multicolrule/issues/2). With multicolrule, the grid is also destroyed when extend-bot is used. This is because immediately after \hbox to\full@width{...} we have \kern-\dimen\tw@ to back up to the baseline, but if the extended depth differs from \dimen\tw@ we could end up at the wrong position. Also, multicolrule uses \rule instead of the primitive \vrule, which means <columnbox> <hbox with vrule nested> <columnbox> rather than <columnbox> <vrule> <columnbox>. There’s also the desire to load as fewer packages as possible: Any extra package add time (and cost, and headache) to maintain existing infrastructure.

The criticisms above should perhaps be brought to multicolrule. But that’s not my point here. I feel like solving one problem while introducing a lot more other problems, so I don’t see how this is a nice solution.

I recall Knuth once joked about why he doesn’t use LaTeX because large software system “scares” him. I share a similar sentiment, which is why I proposed options 1 and 2. If something can be done from the source, that’d be great; if not, that’d be a pity, but there’re still ways to hack into or work around the source code anyway.

For option 1 though, I always wondered why the letter p was chosen in the first place. A parenthesis ( (as in \mathstrut) has full-body height of 1em and makes much more sense. Of course now you can’t just switch to parenthesis because old documents could reflow

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity.