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.
5
  • 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. Nov 13, 2022 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. :-) Nov 13, 2022 at 23:44
  • the bigfoot package might help...
    – Robert
    Nov 14, 2022 at 1:01
  • The magazine library of tcolorbox package has potential (particularly in combination with ekdosis package). I will investigate.
    – Cicada
    Nov 16, 2022 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). Nov 16, 2022 at 16:18

2 Answers 2

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}
14
  • 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. Nov 16, 2022 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. Nov 16, 2022 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. Nov 16, 2022 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, 2022 at 4: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, 2022 at 4:30
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

2
  • 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). Nov 16, 2022 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! Nov 16, 2022 at 16:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .