9

In any system (I'm open to LaTeX, ConTeXt, plain TeX, OPmac, whatever works), I'd like to typeset four running streams of text—source text, commentary A, commentary B, commentary C—and break them into pages, such that they occur one below the other on a typical page (see image below). The catch is that the texts can greatly vary in length:

  • sometimes several pages in source text may not have any commentary, and
  • sometimes a single sentence in the source text may have several pages of commentary.

So the main task is that of automatic page-breaking, by tracking the accumulated lengths of the four (or however many) streams, breaking whenever needed, and continuing across pages. Existing LaTeX packages like reledmac are not designed for this use-case, and cannot handle this (example).

I'm tagging this with ConTeXt and OPmac even though I'm open to any system, simply because I think LuaTeX may be helpful here.


Background: For Sanskrit books, it is traditional to typeset a text along with its commentaries, as in the page below. (Some more examples of the desired page layout, found by searching at archive.org for "three commentaries" etc: here, here, here, here)

example page

Here is a MWE of the desired result (with a source text and two commentaries A and B), but with page breaks chosen manually. We would like to achieve the same result without having to manually choose the location of each break.

\documentclass{article}

\usepackage[papersize={4in,4in}, total={3in,3in}]{geometry}

% A "\Repeat" command: https://tex.stackexchange.com/a/16192 \usepackage{expl3} \ExplSyntaxOn \cs_new_eq:NN \Repeat \prg_replicate:nn \ExplSyntaxOff

\begin{document}

\parindent=0pt \parskip=0.5\baselineskip

% Start: 5 sentences of commentary for each source sentence.

Source text sentence number 1. Source text sentence number 2. Source text sentence number 3.

\medskip \hrule

{\footnotesize \Repeat{5}{Commentary A on sentence 1. } \Repeat{5}{Commentary A on sentence 2. } \Repeat{4}{Commentary A on sentence 3. } Commentary A on senten- }

\medskip \hrule

{\footnotesize \Repeat{5}{Commentary B on sentence 1. } \Repeat{5}{Commentary B on sentence 2. } \Repeat{3}{Commentary B on sentence 3. } Co- }

\newpage

% Continued. Long lengths: % 10 lines of commentary each on sentence 4. % 15 lines of commentary each on sentence 5 (partly fits here).

Source text sentence 4. Source text sentence 5. S-

\medskip \hrule

{\footnotesize ce 3. \Repeat{10}{Commentary A on sentence 4. } \Repeat{4}{Commentary A on sentence 5. } Commentary }

\medskip \hrule

{\footnotesize mmentary B on sentence 3. Commentary B on sentence 3. \Repeat{10}{Commentary B on sentence 4. } \Repeat{3}{Commentary B on sentence 5. } Co- }

\newpage

% Continued: note only commentary on this page.

\hrule

{\footnotesize A on sentence 5. \Repeat{15}{Commentary A on sentence 5. } }

\medskip \hrule

{\footnotesize mmentary B on sentence 5. \Repeat{12}{Commentary B on sentence 5. } Commen- }

\newpage

% Continued: source text continues. % Sentences 6 to 10 have no commentary.

ource text sentence 6. Source text sentence 7. Source text sentence 8. Source text sentence 9. Source text sentence 10.

\medskip \hrule

\medskip \hrule

{\footnotesize tary B on sentence 5. \Repeat{3}{Commentary B on sentence 5. } }

\end{document}

Result:

desired output


Attempt with bigfoot: sort of works, but text runs off the bottom of the page and is lost.

\documentclass{article}
\usepackage[papersize={4in,4in}, total={3in,3in}]{geometry}

\usepackage{lipsum}

\usepackage{bigfoot} \DeclareNewFootnote[para]{A} \DeclareNewFootnote[para]{B}[alph]

\begin{document}

% Several paragraphs of commentary that occur before the first word of the text. \footnoteA{\lipsum[1-4]}

firstword\footnoteA{\lipsum[5-8]} secondword\footnoteA{\lipsum[9-12]} (1)\footnoteB{a few words}

thirdword\footnoteA{\lipsum[13]} fourthword\footnoteA{\lipsum[14-16]} (2)

\end{document}

First few pages of result:

bigfoot result

(Note the wasted space on page 3, and the overflow/truncation on page 4.)


I imagine an algorithm something like the following would work:

  • Given a source text S, and commentaries C1, C2, C3 (where "3" stands for an arbitrary small number), which are divided into matching "units" of the form (s, c1, c2, c3).
  • Maintain (vertical) lists lines[S], lines[C1], lines[C2], lines[C3], each initially empty.
  • For each unit (s, c1, c2, c3),
    • Typeset (i.e. break into lines) each of these, and append the lines to lines[S], lines[C1], lines[C2], lines[C3] respectively.
    • If the total current height of lines[S] + lines[C1] + lines[C2] + lines[C3] is still less than the page height, continue.
    • Otherwise, fill the current page with some appropriate fraction of these four lines, and repeat until the total height becomes less than a page's height.
  • Finally, flush the remaining contents of the four lists.
ShreevatsaR
  • 45,428
  • 10
  • 117
  • 149
  • 1
    The algorithm that you describe seems really similar to how footnotes are typeset, so I think that you could probably reproduce this with \inserts/modified footnotes. I don't think that LuaTeX would be particularly helpful here, although it may make one or two things easier. – Max Chernoff Nov 13 '22 at 23:32
  • @MaxChernoff If you can actually achieve this with footnotes (or anything else) please post an answer; a lot of people (trying to typeset Sanskrit works) would be very grateful. :-) – ShreevatsaR Nov 13 '22 at 23:44
  • the bigfoot package might help... – Robert Nov 14 '22 at 01:01
  • The magazine library of tcolorbox package has potential (particularly in combination with ekdosis package). I will investigate. – Cicada Nov 16 '22 at 14:10
  • @Robert Thanks for the bigfoot suggestion; it indeed looked promising at first but it doesn't handle multiple-paragraph footnotes well (see example added to the question). – ShreevatsaR Nov 16 '22 at 16:18

2 Answers2

2

Stage 2 version --

Another half a step forward: somewhat automated with parameterized input and output.

comm 1

comm 2 part 1

comm 2 part 2

MWE

\documentclass{article}

\usepackage[papersize={4in,6in}, total={3in,5in}]{geometry}

\usepackage{xcolor} \usepackage{fontspec} \setmainfont{Noto Serif}%[Colour=blue] \usepackage{tcolorbox} \tcbuselibrary{skins} \tcbuselibrary{breakable} \tcbuselibrary{magazine} \usetikzlibrary{decorations.pathmorphing}

\usepackage{ekdosis} \SetLineation{lineation=none}

\FormatDiv{1}{\begin{center}\Large}{\end{center}} \FormatDiv{2}{\begin{center}\large}{\end{center}} \FormatDiv{3}{\bfseries}{.}

%\SetDefaultApparatus{rec1} %\DeclareApparatus{rec1} % new layer set as default %\DeclareApparatus{rec2} % additional layer below the default one %\DeclareApparatus{rec3}

%\SetHooks{lemmastyle=\bfseries\color{red},} % %\setlength{\columnseprule}{0.4pt}

\newcommand\comm[1]{\hrule\vspace{0.25ex}#1} \newcommand\commA{\comm{A}} \newcommand\commB{\comm{B}} \newcommand\commC{\comm{C}}

\newboxarray{commA} \newboxarray{commB} \newboxarray{commC}

\newcommand\breakatcommon{3cm/3cm} \newcommand\breakatA{\breakatcommon} \newcommand\breakatB{\breakatcommon} \newcommand\breakatC{\breakatcommon}

\ExplSyntaxOn

    \cs_generate_variant:Nn 
        \seq_gset_split:Nnn 
        { cno }


\tl_new:N \g_comm_Amapin_tl \tl_new:N \g_comm_Bmapin_tl \tl_new:N \g_comm_Cmapin_tl

\tl_new:N \g_comm_Amapout_tl \tl_new:N \g_comm_Bmapout_tl \tl_new:N \g_comm_Cmapout_tl \tl_new:N \g_comm_mapout_tl

\seq_new:N \g_comm_Amapout_seq \seq_new:N \g_comm_Bmapout_seq \seq_new:N \g_comm_Cmapout_seq \seq_new:N \g_comm_mapout_seq

%\int_new:N \g_comm_maxpart_int

\int_new:N \g_comm_Amapout_int \int_new:N \g_comm_Bmapout_int \int_new:N \g_comm_Cmapout_int

\int_new:N \g_comm_collected_int \int_new:N \g_comm_tocollect_int

\int_new:N \g_comm_pagenum_int

\int_new:N \g_comm_Aparonpage_int \int_new:N \g_comm_Bparonpage_int \int_new:N \g_comm_Cparonpage_int

\bool_new:N \g_comm_collectible_bool \bool_new:N \g_comm_source_bool

%----------------------------------------------------- \NewDocumentCommand { \checksourcestatus } { } {

        \bool_if:nTF {
             {\int_compare_p:nNn
               { \g_comm_Amapout_int } < { \mysizeA }}
                ||
             {\int_compare_p:nNn
               { \g_comm_Bmapout_int } < { \mysizeB }}
                ||
             {\int_compare_p:nNn
               { \g_comm_Cmapout_int } < { \mysizeC }}
        }
        { % T: more to process
                \bool_gset_true:N \g_comm_source_bool
        }
        { % F: no more to process
                \bool_gset_false:N \g_comm_source_bool
        }


}

%----------------------------------------------------- \NewDocumentCommand { \checkcollectstatus } { } {

        \bool_if:nTF 
        {
            %:
            {
                % A &B & C
                \seq_if_empty_p:N \g_comm_Amapout_seq
                &&
                \seq_if_empty_p:N \g_comm_Bmapout_seq
                &&
                \seq_if_empty_p:N \g_comm_Cmapout_seq
                }
            %or
            ||
            {
             \int_compare_p:n
               { \g_comm_collected_int >= \g_comm_tocollect_int }
            }

        }
        { % T: no more to collect
                \bool_gset_false:N \g_comm_collectible_bool
        }
        { % F: more to collect
                \bool_gset_true:N \g_comm_collectible_bool
        }


}

%----------------------------------------------------- \NewDocumentCommand { \setABCmapout } { m } { % 1 = seq name

    \tl_gset:Nx \g_comm_currseqname_tl { #1 }

%output: \tl_gclear:N \g_comm_Amapout_tl \tl_gclear:N \g_comm_Bmapout_tl \tl_gclear:N \g_comm_Cmapout_tl \tl_gclear:N \g_comm_mapout_tl

%===================

\tl_if_empty:NF \g_comm_Amapin_tl { \seq_gset_split:NnV \g_comm_Amapout_seq {} \g_comm_Amapin_tl \int_gincr:N \g_comm_Amapout_int
}

\tl_if_empty:NF \g_comm_Bmapin_tl { \seq_gset_split:NnV \g_comm_Bmapout_seq {} \g_comm_Bmapin_tl \int_gincr:N \g_comm_Bmapout_int
}

\tl_if_empty:NF \g_comm_Cmapin_tl { \seq_gset_split:NnV \g_comm_Cmapout_seq {} \g_comm_Cmapin_tl \int_gincr:N \g_comm_Cmapout_int
}

% \seq_show:N % \g_comm_Cmapout_seq

                \checksourcestatus

% \bool_show:N \g_comm_source_bool \int_gset:Nn \g_comm_pagenum_int { 0 }

        \bool_while_do:Nn \g_comm_source_bool
        {

% \checksourcestatus

                \int_gincr:N \g_comm_pagenum_int                    


                \int_gset:Nn \g_comm_collected_int { 0 }

%1st page %%% \int_compare:nNnTF %%% { \g_comm_pagenum_int } = { 1 } %%% { \int_gset:Nn \g_comm_tocollect_int { 3 } %%% }
%%% { %%% \int_gset:Nn \g_comm_tocollect_int { 4 } %%% }

            \int_set:Nn \g_comm_collected_int { 0 }

            \checkcollectstatus

%\bool_show:N \g_comm_collectible_bool

                \newpage

% for each page: \int_gset:Nn \g_comm_Aparonpage_int { 0 } \int_gset:Nn \g_comm_Bparonpage_int { 0 } \int_gset:Nn \g_comm_Cparonpage_int { 0 }

%1st page \int_compare:nNnT { \g_comm_pagenum_int } = { 1 } { \mfsgetitem{\tl_use:N \g_comm_currseqname_tl}{1} %%%%% current sequence

\int_gset:Nn
        \g_comm_Amapout_int
        { 0 }
\int_gset:Nn
        \g_comm_Bmapout_int
        { 0 }
\int_gset:Nn
        \g_comm_Cmapout_int
        { 0 }
            }       


        \bool_while_do:Nn \g_comm_collectible_bool
        {

% \checksourcestatus

% commA: \seq_if_empty:NF \g_comm_Amapout_seq { \int_gincr:N \g_comm_Amapout_int \int_gincr:N \g_comm_Aparonpage_int

    \int_compare:nNnT
      { \g_comm_Aparonpage_int } = { 1 }
       {
                    \ekddiv{head={\commA}, type=paragraph, depth=2, n=II.1.A}
            }       

\tex_par:D \noindent\useboxarray[commA]{\int_use:N \g_comm_Amapout_int } %\seq_show:N \g_comm_Amapout_seq
\seq_gpop_left:NN \g_comm_Amapout_seq \l_tmpa_tl %\seq_show:N \g_comm_Amapout_seq
\int_gincr:N \g_comm_collected_int \checkcollectstatus }

% commB: \seq_if_empty:NF \g_comm_Bmapout_seq { \int_gincr:N \g_comm_Bmapout_int \int_gincr:N \g_comm_Bparonpage_int \int_compare:nNnT { \g_comm_Bparonpage_int } = { 1 } { \ekddiv{head={\commB}, type=paragraph, depth=2, n=II.1.B} }
\tex_par:D \noindent\useboxarray[commB]{\int_use:N \g_comm_Bmapout_int } \seq_gpop_left:NN \g_comm_Bmapout_seq \l_tmpa_tl \int_gincr:N \g_comm_collected_int \checkcollectstatus }

% commC: \seq_if_empty:NF \g_comm_Cmapout_seq { \int_gincr:N \g_comm_Cmapout_int \int_gincr:N \g_comm_Cparonpage_int \int_compare:nNnT { \g_comm_Cparonpage_int } = { 1 } { \ekddiv{head={\commC}, type=paragraph, depth=2, n=II.1.C} }
\tex_par:D \noindent\useboxarray[commC]{\int_use:N \g_comm_Cmapout_int } \seq_gpop_left:NN \g_comm_Cmapout_seq \l_tmpa_tl \int_gincr:N \g_comm_collected_int \checkcollectstatus }

} % while collectible 

\checksourcestatus

% \bool_show:N \g_comm_source_bool

} % while source 

}

\NewDocumentCommand { \setABCmapin } { } {

\boxarraygetsize[commA]{\mysizeA} \boxarraygetsize[commB]{\mysizeB} \boxarraygetsize[commC]{\mysizeC}

\tl_gset:Nx \g_comm_Amapin_tl { \prg_replicate:nn { \mysizeA } { A } }

\tl_gset:Nx \g_comm_Bmapin_tl { \prg_replicate:nn { \mysizeB } { B } }

\tl_gset:Nx \g_comm_Cmapin_tl { \prg_replicate:nn { \mysizeC } { C } } %\tl_show:N % \g_comm_Cmapin_tl }

\NewDocumentCommand { \mfsgetitem } { o m m } { % 1=namespace % 2=seq name % 3=item

            \IfNoValueTF { #1 } 
                    { \tl_clear:N \g_fc_namespace_tl } 
                    { \tl_gset:Nn \g_fc_namespace_tl { #1 } }



\tl_set:Nx
        \l_tmpa_tl
        {
            \seq_item:cn
                    { g_fc_rwe \g_fc_namespace_tl #2 _seq }
                    { #3 }
        }

\tl_use:N
        \l_tmpa_tl

}

\tl_new:N \g_comm_currseqname_tl

\NewDocumentCommand { \mfsloadaseql } { o m m +m } { % 1=namespace % 2=seq name % 3=sep % 4=data

            \IfNoValueTF { #1 } 
                    { \tl_clear:N \g_fc_namespace_tl } 
                    { \tl_gset:Nn \g_fc_namespace_tl { #1 } }

% \tl_gset:Nx \g_comm_currseqname_tl { #2 }

\cs_if_free:cT
        { g_fc_rwe \g_fc_namespace_tl #2 _seq }
        { \seq_new:c
                { g_fc_rwe \g_fc_namespace_tl #2 _seq } 
        }

\seq_gclear:c 
        { g_fc_rwe \g_fc_namespace_tl #2 _seq } 
\seq_gset_split:cno 
        { g_fc_rwe \g_fc_namespace_tl #2 _seq } 
        { #3 } 
        { #4 }

}

\ExplSyntaxOff

\newcommand\boxcommA[1]{% \begin{tcolorbox}[enhanced jigsaw,size=fbox,width=\textwidth, colback=yellow!10,colframe=yellow!10!black, fontupper=\footnotesize, breakable,% use only breakable in the real world! break at=\breakatA, height fixed for=none, watermark text=A\arabic{tcbbreakpart}, reset box array=commA, store to box array=commA, extras last={ borderline south={0.25mm}{-0.5mm}{blue,decoration={zigzag,amplitude=0.5mm},decorate}}, extras unbroken and last={ borderline south={0.25mm}{-0.5mm}{blue,decoration={zigzag,amplitude=0.5mm},decorate}}, ] #1 \end{tcolorbox} }

\newcommand\boxcommB[1]{% \begin{tcolorbox}[enhanced jigsaw,size=fbox,width=\textwidth, colback=blue!10,colframe=yellow!10!black, fontupper=\footnotesize, breakable,% use only breakable in the real world! break at=\breakatB, height fixed for=none, watermark text=B\arabic{tcbbreakpart}, reset box array=commB, store to box array=commB, extras last={ borderline south={0.25mm}{-0.5mm}{blue,decoration={zigzag,amplitude=0.5mm},decorate}}, extras unbroken and last={ borderline south={0.25mm}{-0.5mm}{blue,decoration={zigzag,amplitude=0.5mm},decorate}}, ] #1 \end{tcolorbox} }

\newcommand\boxcommC[1]{% \begin{tcolorbox}[enhanced jigsaw,size=fbox,width=\textwidth, colback=green!10,colframe=red!10!black, fontupper=\footnotesize, breakable,% use only breakable in the real world! break at=\breakatC, height fixed for=none, watermark text=C\arabic{tcbbreakpart}, reset box array=commC, store to box array=commC, extras last={ borderline south={0.25mm}{-0.5mm}{blue,decoration={zigzag,amplitude=0.5mm},decorate}}, extras unbroken and last={ borderline south={0.25mm}{-0.5mm}{blue,decoration={zigzag,amplitude=0.5mm},decorate}}, ] #1 \end{tcolorbox} }

\newcommand\docommentarypart[1]{ \begin{ekdosis} \boxcommA{\mfsgetitem{#1}{2}} \boxcommB{\mfsgetitem{#1}{3}} \boxcommC{\mfsgetitem{#1}{4}} \setABCmapin \setABCmapout{#1} \end{ekdosis} }

\input{commdata.tex}

\begin{document}

Commentaries

%======================= \docommentarypart{c1}

%======================= \docommentarypart{c2}

\end{document}

The input file, commdata.tex, is:

\mfsloadaseql{c1}{comm}{%
Source text sentence number 1.
Source text sentence number 2.
Source text sentence number 3.
comm A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A

A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A comm Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B

Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B

Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B comm Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C }

%================================== \mfsloadaseql{c2}{commx}{% Extracts from Wikipedia for the Solar System, Venus, and Mars. commx The Solar System[c] is the gravitationally bound system of the Sun and the objects that orbit it. It formed 4.6 billion years ago from the gravitational collapse of a giant interstellar molecular cloud. The vast majority (99.86%) of the system's mass is in the Sun, with most of the remaining mass contained in the planet Jupiter. The four inner system planets—Mercury, Venus, Earth and Mars—are terrestrial planets, being composed primarily of rock and metal. The four giant planets of the outer system are substantially larger and more massive than the terrestrials. The two largest, Jupiter and Saturn, are gas giants, being composed mainly of hydrogen and helium; the next two, Uranus and Neptune, are ice giants, being composed mostly of volatile substances with relatively high melting points compared with hydrogen and helium, such as water, ammonia, and methane. All eight planets have nearly circular orbits that lie near the plane of Earth's orbit, called the ecliptic. commx Venus is the second planet from the Sun. It is sometimes called Earth's "sister" or "twin" planet as it is almost as large and has a similar composition. As an interior planet to Earth, Venus (like Mercury) appears in Earth's sky never far from the Sun, either as morning star or evening star. Aside from the Sun and Moon, Venus is the brightest natural object in Earth's sky, capable of casting visible shadows on Earth at dark conditions and being visible to the naked eye in broad daylight.[18][19]

Venus is the second largest terrestrial object of the Solar System, with a surface gravity minimally lower than on Earth, but having only an induced magnetosphere. The carbon dioxide atmosphere of Venus is the densest of the four terrestrial planets. The atmospheric pressure at the planet's surface is about 92 times the sea level pressure of Earth, or roughly the pressure at 900 m (3,000 ft) underwater on Earth. Even though Mercury is closer to the Sun, Venus has the hottest surface of any planet in the Solar System, with a mean temperature of 737 K (464 °C; 867 °F). Venus is shrouded by an opaque layer of highly reflective clouds of sulfuric acid, making it the planet with the highest albedo in the Solar System and preventing its surface from being seen from Earth in light. It may have had water oceans in the past,[20][21] but after these evaporated the temperature rose under a runaway greenhouse effect.[22] The water has probably photodissociated, and the free hydrogen has been swept into interplanetary space by the solar wind because of the lack of an internally induced magnetic field.[23] At roughly 50 km above the surface atmospheric conditions reach Earth-like temperatures and levels of pressure. The possibility of life on Venus has long been a topic of speculation but convincing evidence has yet to be found. commx Mars is the fourth planet from the Sun and the second-smallest planet in the Solar System, being larger than only Mercury. In the English language, Mars is named for the Roman god of war. Mars is a terrestrial planet with a thin atmosphere (less than 1% that of Earth's), and has a crust primarily composed of elements similar to Earth's crust, as well as a core made of iron and nickel. Mars has surface features such as impact craters, valleys, dunes, and polar ice caps. It has two small and irregularly shaped moons: Phobos and Deimos.

Some of the most notable surface features on Mars include Olympus Mons, the largest volcano and highest known mountain on any planet in the Solar System, and Valles Marineris, one of the largest canyons in the Solar System. The Borealis basin in the Northern Hemisphere covers approximately 40% of the planet and may be a large impact feature.[20] Days and seasons on Mars are comparable to those of Earth, as the planets have a similar rotation period and tilt of the rotational axis relative to the ecliptic plane. Liquid water on the surface of Mars cannot exist due to low atmospheric pressure, which is less than 1% of the atmospheric pressure on Earth.[21][22] Both of Mars's polar ice caps appear to be made largely of water.[23][24] In the distant past, Mars was likely wetter, and thus possibly more suited for life. However, it is unknown whether life has ever existed on Mars. }


Stage 1 (manual; proof of concept)

page 1

page 2

With each ekdosis division containing a tcolorbox stored as an array of breakable boxes, and their heights known, it should be possible, as a start, to calculate where to dynamically insert a pagebreak for any box array items N>=2.

MWE

\documentclass{article}

\usepackage[papersize={4in,6in}, total={3in,5in}]{geometry}

\usepackage{xcolor} \usepackage{fontspec} \setmainfont{Noto Serif}%[Colour=blue] \usepackage{tcolorbox} \tcbuselibrary{skins} \tcbuselibrary{breakable} \tcbuselibrary{magazine}

\usepackage{ekdosis} \SetLineation{lineation=none}

\FormatDiv{1}{\begin{center}\Large}{\end{center}} \FormatDiv{2}{\begin{center}\large}{\end{center}} \FormatDiv{3}{\bfseries}{.}

\SetDefaultApparatus{rec1} \DeclareApparatus{rec1} % new layer set as default \DeclareApparatus{rec2} % additional layer below the default one \DeclareApparatus{rec3}

\SetHooks{lemmastyle=\bfseries\color{red},}

\setlength{\columnseprule}{0.4pt}

\newcommand\comm[1]{\hrule\vspace{0.25ex}#1} \newcommand\commA{\comm{A}} \newcommand\commB{\comm{B}} \newcommand\commC{\comm{C}}

\newboxarray{commA} \newboxarray{commC}

\begin{document}

Commentaries

\begin{ekdosis} \ekddiv{ head={XXX}, type=section, depth=1, n=I } Source text sentence number 1. Source text sentence number 2. Source text sentence number 3. %Source text sentence 4. %Source text sentence 5. %Source text sentence 6. %Source text sentence 7. %Source text sentence 8. %Source text sentence 9. %Source text sentence 10.

\ekddiv{ head={\commA}, type=paragraph, depth=2, n=II.1.A } \begin{tcolorbox}[enhanced jigsaw,size=fbox,width=\textwidth, colback=yellow!10,colframe=white, fontupper=\footnotesize, breakable,% use only breakable in the real world! break at=2cm/2cm, height fixed for=all, watermark text=\arabic{tcbbreakpart}, reset box array=commA, store to box array=commA, ] A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A

A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A \end{tcolorbox} \noindent\useboxarray[commA]{1}

\ekddiv{head=\commB, type=paragraph, depth=2, n=II.1.B} \begin{tcolorbox}[enhanced jigsaw,size=fbox,width=\textwidth, colback=blue!10,colframe=yellow!10!black, fontupper=\footnotesize, breakable,% use only breakable in the real world! break at=2cm/2cm, height fixed for=all, watermark text=\arabic{tcbbreakpart}, reset box array, store to box array ] Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B

Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B

Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B Text B \end{tcolorbox} \noindent\useboxarray{1}

\ekddiv{head={\commC}, type=paragraph, depth=2, n=II.1.C}

\begin{tcolorbox}[enhanced jigsaw,size=fbox,width=\textwidth, colback=green!10,colframe=yellow!10!black, fontupper=\footnotesize, breakable,% use only breakable in the real world! break at=2cm/2cm, height fixed for=all, watermark text=\arabic{tcbbreakpart}, reset box array=commC, store to box array=commC, ] Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C Text C \end{tcolorbox} \noindent\useboxarray[commC]{1}

\newpage \ekddiv{head={\commA}, type=paragraph, depth=2, n=II.1.C} \boxarraygetsize[commA]{\mysizeA} \foreach \n in {2,...,\mysizeA} { \noindent\useboxarray[commA]{\n} }

\ekddiv{head={\commB}, type=paragraph, depth=2, n=II.1.C}

\boxarraygetsize{\mysizeB} \foreach \n in {2,...,\mysizeB} { \noindent\useboxarray{\n} }

\ekddiv{head={\commC}, type=paragraph, depth=2, n=II.1.C}

\boxarraygetsize[commA]{\mysizeC} \foreach \n in {2,...,\mysizeC} { \noindent\useboxarray[commC]{\n} }

\end{ekdosis}

\end{document}

Cicada
  • 10,129
  • Thanks I'll take a look… I just added an example to the question using bigfoot (based on real-life Sanskrit example that someone shared with me); I'll try this solution with a similar example. – ShreevatsaR Nov 16 '22 at 16:20
  • This example works and it may need latexmk running while the composer adds text to find how much text of original and each commentaries need to be added. So, no automation of flow. – lalitaalaalitah Nov 16 '22 at 19:02
  • And a very simple addition of lengthy commentaries has broken this example, as was the case of bigfoot. I'll share them same with @ShreevatsaR privately. – lalitaalaalitah Nov 16 '22 at 19:09
  • @lalitaalaalitah Thanks. The code is only illustration of possible path; it hard-codes the pagebreak - it needs to become a dynamic calc (both sides of pagebreak) to become actual example for potential build effort. Token lists are not limited in length (except by system/registers), so could be entire document(s). What does "broken" mean? – Cicada Nov 17 '22 at 04:24
  • Full automation will ultimately be lua code to build the four-stream text input variable (the textual unit) and then feed it into the page-formatter function. But some human-input markdown/tagging will be need to tell TeX what the 4-text unit actually is because it doesn't know - perhaps some sort of \commentary[ABC]{} tag functioning like \footnote or \index. – Cicada Nov 17 '22 at 04:30
  • I'm trying to understand what this is and how to use it: do I understand correctly that the first part simply stores the texts of the "streams" (source, A, B, C) separately into breakable tcolorboxes, and the second part (after the \newpage) is the one that actually uses the contents, and somehow magically breaks to just the right heights? – ShreevatsaR Nov 18 '22 at 05:45
  • Am trying out various auto page-breaking methods and intend to add a "Stage 2" to the post. Should be 3-4 stages, ultimately. In meantime: What should pages 2,...,n of commentaries look like if A is 3pp, B10pp, C 1 paragraph? Are fractional pages allowed? I haven't seen any yet. (If yes, can you add links to examples?). Is pageheight-to-comment par-height ratio significant? (If yes, that implies each page is hand-crafted - correct? i.e., each page is in thirds or quarters: correct? Coding will need multiple parameters to imitate, not impossible - which parameters?). – Cicada Nov 18 '22 at 09:55
  • @Cicada Thank you for looking into this! To answer the questions: I think one thing publishers want is to use up all available paper, i.e no "wasted" whitespace :) It is ok (and expected) to vary the heights of A, B, C. E.g. in your example, maybe page 1 will have a bit of all three commentaries, pages 2–3 (or so) will have only A and B (occupying roughly half the page each), while the rest of the pages will have only B. Does that make sense? (Let me see if I can find or add an example...) – ShreevatsaR Nov 18 '22 at 15:33
  • Optimized maximal page-filling implies that there must be (allowed) customized settings per commentary (usually this will be done with manual adjustments, after auto output has been seen): e.g., for the tcolorbox method, use of enlargepage flexible=, break at=, height fixed for= etc etc (see manual for all the options) will have different values per box, not the same for every box. This requirement affects all solution methods, not just tcolorbox one like in this case. What about font size? Main audience is the hardcopy publisher, not the reader, correct? – Cicada Nov 19 '22 at 03:30
  • The reledmac method, of boxing the text and then putting it line by line onto the page, adjusting as it goes, is likely the way to go, only x4 and, I expect, with multiple read-writes to external files. Alternative is lua code does everything (not impossible, but not a 5-minute job either). Perhaps there is a package that already does this (like a row-version of multicol, in effect). – Cicada Nov 19 '22 at 06:39
  • \vbox_set_split_to_ht:NNn command in expl3 looks very promising; the one remaining algorithm hurdle is how to interleave 4 input streams at line-level. – Cicada Nov 19 '22 at 15:49
  • @Cicada, Sorry for using the term loosely. I just meant that lines were overflowing the bottom margin and missing, as was the case of bigfoot. – lalitaalaalitah Nov 20 '22 at 08:21
  • @lalitaalaalitah No worries. Stage 1 code has only 1 (manual) pagebreak, for illustration of specification of structure and as tcb POC. Stage 2 has attempt at auto-pagebreak algorithm but "flush the remaining contents of the four lists" (where 98% of the build work is) is somewhat vague and can be implemented in multiple ways with guessing - we really need a detailed specification. – Cicada Nov 20 '22 at 10:20
  • Very interesting discussion. It may be worth mentioning that the development version of ekdosis provides a maxlines option which may prove useful for editions equipped with long and complex set of critical notes. This mechanism requires adjustments now, but it will be improved in the releases to come. – Robert Alessi Dec 15 '22 at 06:11
1

I'm not sure that I completely understand the question (my mind and/or memory is not what it was), but...

The memoir class (an extended version of book) provides for several classes/series of footnotes.

For details please read the manual (texdoc memoir) 12.1.1 A variety of footnotes

Peter Wilson
  • 28,066
  • I'm sorry that the question is not very clear. I just moved my suggested algorithm to the bottom, as it is not part of the question proper. Could you say at point the question becomes unclear, so that I can rewrite it from there on? (If it's unclear from the very first word, please let me know as well.) In the meantime, I'll also add a minimal example using the suggested bigfoot and memoir to the question, to show why they don't work (at least, as far as I can tell). – ShreevatsaR Nov 16 '22 at 15:05
  • I've added an example to the question that uses bigfoot (search for "Attempt with bigfoot"); please see whether it makes sense / makes the question easier to understand. Thank you! – ShreevatsaR Nov 16 '22 at 16:26