%D \module %D [ file=spac-par, %D version=2009.10.16, % 1997.03.31, was core-spa.tex %D title=\CONTEXT\ Spacing Macros, %D subtitle=Paragraphs, %D author=Hans Hagen, %D date=\currentdate, %D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. \writestatus{loading}{ConTeXt Spacing Macros / Paragraphs} \registerctxluafile{spac-par}{autosuffix} \unprotect % TODO: \appendtoks \strut \wrapuppar{\strut}\to \everypar % this might move to syst-ini.mkxl \setnewconstant\frozenparagraphdefault\numexpr \adjustfrozenparcode + \brokenpenaltyfrozenparcode + \clubpenaltyfrozenparcode + \demeritsfrozenparcode + \displaypenaltyfrozenparcode + \emergencyfrozenparcode + \exhyphenpenaltyfrozenparcode + \fitnessclassesfrozenparcode + \hangfrozenparcode + \hsizefrozenparcode + \hyphenationfrozenparcode + \hyphenpenaltyfrozenparcode + \indentfrozenparcode + \lastlinefrozenparcode + \linebreakchecksfrozenparcode % \linefrozenparcode + \linepenaltyfrozenparcode + \loosenessfrozenparcode % \mathpenaltyfrozenparcode + \orphanpenaltyfrozenparcode + \parfillfrozenparcode + \parpassesfrozenparcode + \protrudefrozenparcode + \shapefrozenparcode + \shapingpenaltyfrozenparcode + \singlelinepenaltyfrozenparcode + \skipfrozenparcode + \stretchfrozenparcode + \toddlerpenaltyfrozenparcode + \tolerancefrozenparcode + \twindemeritsfrozenparcode + \widowpenaltyfrozenparcode \relax \setnewconstant\paragraphupdatecodes\numexpr \tolerancefrozenparcode + \loosenessfrozenparcode + \linepenaltyfrozenparcode + \widowpenaltyfrozenparcode + \clubpenaltyfrozenparcode + \brokenpenaltyfrozenparcode + \demeritsfrozenparcode + \orphanpenaltyfrozenparcode + \toddlerpenaltyfrozenparcode + \singlelinepenaltyfrozenparcode + \hyphenpenaltyfrozenparcode + \exhyphenpenaltyfrozenparcode + \linebreakchecksfrozenparcode + \twindemeritsfrozenparcode \relax \setnewconstant\paragraphpenaltycodes\numexpr \linepenaltyfrozenparcode + \widowpenaltyfrozenparcode + \clubpenaltyfrozenparcode + \brokenpenaltyfrozenparcode + \shapingpenaltyfrozenparcode + \orphanpenaltyfrozenparcode + \toddlerpenaltyfrozenparcode + \singlelinepenaltyfrozenparcode + \hyphenpenaltyfrozenparcode + \exhyphenpenaltyfrozenparcode + \linebreakchecksfrozenparcode \relax \setnewconstant\paragraphdemeritcodes\numexpr \demeritsfrozenparcode + \twindemeritsfrozenparcode \relax \setnewconstant\paragraphshapecodes\numexpr \hangfrozenparcode + \skipfrozenparcode + \parfillfrozenparcode + \shapefrozenparcode \relax \setnewconstant\paragraphlinecodes\numexpr \linefrozenparcode \relax \setnewconstant\paragraphhyphenationcodes\numexpr \hyphenationfrozenparcode \relax \setnewconstant\paragraphpassescodes\numexpr \parpassesfrozenparcode \relax \bitwiseflip\glyphoptions\checktoddlerglyphoptioncode \bitwiseflip\glyphoptions\checktwinglyphoptioncode % \linefrozenparcode % lineskip \appendtoks \parpasses\zerocount % \noexpansion % \noprotrusion \to \everyforgetall \permanent\protected\def\freezeparagraphproperties {\snapshotpar\frozenparagraphdefault} \permanent\protected\def\defrostparagraphproperties{\snapshotpar\zerocount} \permanent\protected\def\updateparagraphproperties{\ifhmode\snapshotpar\paragraphupdatecodes \fi} \permanent\protected\def\updateparagraphpenalties {\ifhmode\snapshotpar\paragraphpenaltycodes\fi} \permanent\protected\def\updateparagraphdemerits {\ifhmode\snapshotpar\paragraphdemeritcodes\fi} \permanent\protected\def\updateparagraphshapes {\ifhmode\snapshotpar\paragraphshapecodes \fi} \permanent\protected\def\updateparagraphlines {\ifhmode\snapshotpar\paragraphlinecodes \fi} \permanent\protected\def\updateparagraphpasses {\ifhmode\snapshotpar\paragraphpassescodes \fi} % so far \let\spac_paragraph_freeze\relax \permanent\protected\def\setparagraphfreezing {\enforced\let\spac_paragraph_freeze\freezeparagraphproperties} \permanent\protected\def\forgetparagraphfreezing{\enforced\let\spac_paragraph_freeze\relax} \installcorenamespace {bparwrap} \installcorenamespace {eparwrap} \installcorenamespace {parwrapbefore} \installcorenamespace {parwrapafter} \installcorenamespace {parwrapcount} \lettonothing\spac_paragraph_wrap \newinteger\c_spac_paragraph_group_level \protected\def\spac_paragraph_update {\c_spac_paragraph_group_level\currentgrouplevel\relax \ifcsname\??bparwrap\the\c_spac_paragraph_group_level\endcsname \the\lastnamedcs \relax \dontleavehmode % just in case \wrapuppar{\the\csname\??eparwrap\the\c_spac_paragraph_group_level\endcsname\relax}% \fi} \permanent\protected\def\registerparwrapper {\spac_register_par_wrapper\toksapp\tokspre} \permanent\protected\def\registerparwrapperreverse{\spac_register_par_wrapper\tokspre\toksapp} \protected\def\spac_paragraph_install {\expandafter\newtoks\csname\??bparwrap\the\currentgrouplevel\endcsname \expandafter\newtoks\csname\??eparwrap\the\currentgrouplevel\endcsname} \def\spac_paragraph_install_count#1% {\expandafter\newinteger\csname\??parwrapcount#1\endcsname} \def\spac_paragraph_install_pair#1#2#3% {\expandafter\newtoks\csname\??parwrapbefore#3\endcsname \expandafter\newtoks\csname\??parwrapafter #3\endcsname #1\csname\??bparwrap\the\currentgrouplevel\endcsname{\the\csname\??parwrapbefore#3\endcsname}% #2\csname\??eparwrap\the\currentgrouplevel\endcsname{\the\csname\??parwrapafter #3\endcsname}} \def\spac_register_par_wrapper_yes#1#2#3#4#5% {\ifcsname\??bparwrap\the\currentgrouplevel\endcsname \else \spac_paragraph_install \fi \ifcsname\??parwrapcount#3\endcsname \else \spac_paragraph_install_count{#3}% \fi \ifcsname\??parwrapbefore#3\endcsname \else \spac_paragraph_install_pair#1#2{#3}% \fi #1\csname\??parwrapbefore#3\endcsname{\global\advanceby\csname\??parwrapcount#3\endcsname\plusone\relax % global, see (!) \clf_setparwrapper{#3}#4}% #2\csname\??parwrapafter #3\endcsname{#5}% \clf_newparwrapper{#3}% \let\spac_paragraph_wrap\spac_paragraph_update} \def\spac_register_par_wrapper_nop#1#2#3#4#5% {\ifcsname\??parwrapcount#3\endcsname \else \spac_paragraph_install_count{#3}% \fi \global\csname\??parwrapcount#3\endcsname\plusone % global, see (!) #4\wrapuppar{#5}} \protected\def\spac_register_par_wrapper {\ifhmode \expandafter\spac_register_par_wrapper_nop \else \expandafter\spac_register_par_wrapper_yes \fi} \permanent\protected\def\forgetparwrapper {\csname\??bparwrap\the\currentgrouplevel\endcsname\emptytoks \csname\??eparwrap\the\currentgrouplevel\endcsname\emptytoks} \permanent\protected\def\unregisterparwrapper#1% {\global\csname\??parwrapcount#1\endcsname\zerocount % global, see (!) \ifcsname\??parwrapbefore#1\endcsname \lastnamedcs\emptytoks \csname\??parwrapafter#1\endcsname\emptytoks \fi} \permanent\def\directparwrapper#1#2% {#1\wrapuppar{#2}} \permanent\protected\def\doifelseparwrapper#1% {\unless\ifcsname\??parwrapcount#1\endcsname \expandafter\secondoftwoarguments \orelse\ifcase\lastnamedcs \expandafter\secondoftwoarguments \else \expandafter\firstoftwoarguments \fi} % \getparwrapper % defined in lua % \lastparwrapper % defined in lua \permanent\protected\def\showparwrapperstate#1% {\begingroup \infofont ΒΆ#1\hilo {\smallinfofont\getparwrapper {#1}}% {\smallinfofont\lastparwrapper{#1}}% \endgroup} %appendtoks\updateparwrapperindeed\to\everypar %appendtoks\spac_paragraph_wrap \to\everypar %appendtoks\spac_paragraph_freeze \to\everypar % (!) testcase for global setting of count % % \starttext % \hsize3cm % Aaa\wordright{Aaa}\par % \sc{Bbb\wordright{Bbb}}\par % {\sc Ccc\wordright{Ccc}}\par % \sc{Ddd}\wordright{\sc{Ddd}}\par % \stoptext \setparagraphfreezing \appendtoks\lettonothing\spac_paragraph_wrap\to\everyforgetall %D In due time, the code below will be upgraded using the above mechanisms. %D The dreadful sequence \type {\bgroup} \unknown\ \type {\carryoverpar} \unknown\ %D \type {\egroup} is needed when for instance sidefloats are used in combination %D with something that starts with a group. This is because otherwise the %D indentation as set (by the output routine) inside the group are forgotten %D afterwards. (I must not forget its existence). \mutable\lettonothing\currentparagraphproperties % visible for tracing \permanent\def\carryoverpar#1% #1 can be \endgroup or \egroup or ... expandable ! {\normalexpanded {\noexpand#1% \hangindent\the\hangindent \hangafter \the\hangafter \parskip \the\parskip \leftskip \the\leftskip \rightskip \the\rightskip \relax}} \permanent\protected\def\pushparagraphproperties {\edef\currentparagraphproperties{\carryoverpar\relax}% \pushmacro\currentparagraphproperties} \permanent\protected\def\popparagraphproperties {\popmacro\currentparagraphproperties \currentparagraphproperties} \permanent\protected\def\flushparagraphproperties {\popmacro\currentparagraphproperties} %D Beware, changing this will break some code (like pos/backgrounds) but it has been %D changed anyway so let's see where things go wrong. \installcorenamespace{paragraphintro} \newtoks\t_spac_paragraphs_intro_first \newtoks\t_spac_paragraphs_intro_next \newtoks\t_spac_paragraphs_intro_each \newconditional\c_spac_paragraphs_intro_first \newconditional\c_spac_paragraphs_intro_next \newconditional\c_spac_paragraphs_intro_each \lettonothing\spac_paragraphs_flush_intro \lettonothing\spac_paragraphs_intro_step \permanent\protected\tolerant\def\setupparagraphintro[#1]#*[#2]% {\def\spac_paragraphs_intro_step##1% {\csname\??paragraphintro\ifcsname\??paragraphintro##1\endcsname##1\fi\endcsname{#2}}% \processcommacommand[#1]\spac_paragraphs_intro_step} \letcsname\??paragraphintro\empty\endcsname\gobbleoneargument \defcsname\??paragraphintro\v!reset\endcsname#1% {\global\c_spac_paragraphs_intro_first\conditionalfalse \global\c_spac_paragraphs_intro_next\conditionalfalse \global\c_spac_paragraphs_intro_each\conditionalfalse \global\t_spac_paragraphs_intro_first\emptytoks \global\t_spac_paragraphs_intro_next \emptytoks \global\t_spac_paragraphs_intro_each \emptytoks \glettonothing\spac_paragraphs_flush_intro} \defcsname\??paragraphintro\v!first\endcsname#1% {\global\c_spac_paragraphs_intro_first\conditionaltrue \gtoksapp\t_spac_paragraphs_intro_first{#1}% \glet\spac_paragraphs_flush_intro\spac_paragraphs_flush_intro_indeed} \defcsname\??paragraphintro\v!next\endcsname#1% {\global\c_spac_paragraphs_intro_next\conditionaltrue \gtoksapp\t_spac_paragraphs_intro_next{#1}% \glet\spac_paragraphs_flush_intro\spac_paragraphs_flush_intro_indeed} \defcsname\??paragraphintro\v!each\endcsname#1% {\global\c_spac_paragraphs_intro_each\conditionaltrue \gtoksapp\t_spac_paragraphs_intro_each{#1}% \glet\spac_paragraphs_flush_intro\spac_paragraphs_flush_intro_indeed} %D We can say: %D %D \starttyping %D \setupparagraphintro[first][\index{Knuth}] %D \stoptyping %D %D Maybe more convenient is: %D %D \starttyping %D \flushatparagraph{\index{Zapf}} %D \stoptyping %D %D \starttyping %D \setupparagraphintro[first][\hbox to 3.5em{\tt FIRST \hss}] %D \setupparagraphintro[first][\hbox to 3.5em{\tt TSRIF \hss}] %D \setupparagraphintro[next] [\hbox to 3.5em{\tt NEXT \hss}] %D \setupparagraphintro[next] [\hbox to 3.5em{\tt TXEN \hss}] %D \setupparagraphintro[each] [\hbox to 3.0em{\tt EACH \hss}] %D \setupparagraphintro[each] [\hbox to 3.0em{\tt HCEA \hss}] %D %D some paragraph \par %D some paragraph \par %D some paragraph \par %D some paragraph \par %D %D \setupparagraphintro[first][\hbox to 3.5em{\tt FIRST \hss}] %D \setupparagraphintro[first][\hbox to 3.5em{\tt TSRIF \hss}] %D %D some paragraph \par %D some paragraph \par %D %D \setupparagraphintro[reset] %D %D some paragraph \par %D \stoptyping \permanent\protected\def\flushatparagraph#1% {\global\c_spac_paragraphs_intro_first\plusone \gtoksapp\t_spac_paragraphs_intro_first{#1}% \glet\spac_paragraphs_flush_intro\spac_paragraphs_flush_intro_indeed} %D Here comes the flusher (we misuse the one level expansion of token registers to %D feed a nice stream into the paragraph.) \protected\def\spac_paragraphs_flush_intro_indeed % we make sure that the token lists expand directly {\normalexpanded{% % after another so the first code is there twice \ifconditional\c_spac_paragraphs_intro_each \ifconditional\c_spac_paragraphs_intro_next \glet\spac_paragraphs_flush_intro\spac_paragraphs_flush_intro_next \else \glet\spac_paragraphs_flush_intro\spac_paragraphs_flush_intro_each \fi \ifconditional\c_spac_paragraphs_intro_first \global\c_spac_paragraphs_intro_first\conditionalfalse \global\t_spac_paragraphs_intro_first\emptytoks \expand\t_spac_paragraphs_intro_first \fi \expand\t_spac_paragraphs_intro_each \else \ifconditional\c_spac_paragraphs_intro_next \glet\spac_paragraphs_flush_intro\spac_paragraphs_flush_intro_next \fi \ifconditional\c_spac_paragraphs_intro_first \global\c_spac_paragraphs_intro_first\conditionalfalse \global\t_spac_paragraphs_intro_first\emptytoks \expand\t_spac_paragraphs_intro_first \fi \fi}} \protected\def\spac_paragraphs_flush_intro_next {\normalexpanded{% \global\c_spac_paragraphs_intro_next\conditionalfalse \global\t_spac_paragraphs_intro_next\emptytoks \ifconditional\c_spac_paragraphs_intro_each \glet\spac_paragraphs_flush_intro\spac_paragraphs_flush_intro_each \expand\t_spac_paragraphs_intro_next \expand\t_spac_paragraphs_intro_each \else \glettonothing\spac_paragraphs_flush_intro \expand\t_spac_paragraphs_intro_next \fi}} \protected\def\spac_paragraphs_flush_intro_each {\expand\t_spac_paragraphs_intro_each} %D \macros %D {flushatnextpar} %D %D This macro collects data that will be flushed at the next paragraph. By using %D this macro you can avoid interfering nodes (writes, etc). \lettonothing\flushpostponednodedata % hook into everypar \newbox \b_spac_postponed_data %newinteger\c_spac_postponed_data % \installcorenamespace {postponednodesstack} % % \initializeboxstack\??postponednodesstack % % \protected\def\pushpostponednodedata % {\global\advanceby\c_spac_postponed_data\plusone % \savebox\??postponednodesstack{\the\c_spac_postponed_data}{\box\b_spac_postponed_data}} % % \protected\def\poppostponednodedata % {\global\setbox\b_spac_postponed_data\hbox{\foundbox\??postponednodesstack{\the\c_spac_postponed_data}}% % \global\advanceby\c_spac_postponed_data\minusone % \ifvoid\b_spac_postponed_data\else % \enforced\glet\flushpostponednodedata\spac_postponed_data_flush % \fi} \newtoks\everyflushatnextpar \permanent\protected\def\pushpostponednodedata {\globalpushbox\b_spac_postponed_data} \permanent\protected\def\poppostponednodedata {\globalpopbox\b_spac_postponed_data \ifvoid\b_spac_postponed_data\else \enforced\glet\flushpostponednodedata\spac_postponed_data_flush \fi} \permanent\protected\def\flushatnextpar {\begingroup \expand\everyflushatnextpar \enforced\glet\flushpostponednodedata\spac_postponed_data_flush \dowithnextboxcs\spac_postponed_data_finish\hpack} % \def\spac_postponed_data_finish % {\global\setbox\b_spac_postponed_data\hpack % to\zeropoint % {\box\b_spac_postponed_data\box\nextbox}% % \endgroup} % % This is better when used with protrusion which does not like too deeply nested % boxes: % % \def\spac_postponed_data_finish % {\dontcomplain % \global\setbox\b_spac_postponed_data\hpack to \zeropoint % {\unhbox\b_spac_postponed_data\unhbox\nextbox}% % \endgroup} % % We could do this if there is content with widths ... not that is should be used % that way, but this way we don't overflow: \def\spac_postponed_data_finish {\dontcomplain \global\setbox\b_spac_postponed_data\hpack % to \zeropoint {\unhbox\b_spac_postponed_data \scratchdimen\wd\nextbox \unhbox\nextbox \ifcase\scratchdimen\else\kern-\scratchdimen\fi}% \endgroup} \def\spac_postponed_data_flush {%\iftrialtypesetting \else \ifvoid\b_spac_postponed_data\else \hpack{\smashedbox\b_spac_postponed_data}% \box\b_spac_postponed_data \fi \enforced\glettonothing\flushpostponednodedata }%\fi} \permanent\protected\def\doflushatpar % might be renamed {\ifvmode \expandafter\flushatnextpar \else \expandafter\firstofoneargument \fi} %D Experiment: %D %D \starttyping %D \startcombination[4*1] %D {\vtop{ \hsize #1 \setupalign[tolerant] \samplefile{ward}}} {tolerant} %D {\vtop{\darkblue \hsize #1 \setupalign[tolerant,stretch] \samplefile{ward}}} {tolerant,stretch} %D {\vtop{\darkgreen \hsize #1 \setupalign[tolerant] \optimize[flushleft] \samplefile{ward}}} {tolerant,fuzzy} %D {\vtop{\darkred \hsize #1 \setupalign[tolerant] \optimize[normal] \samplefile{ward}}} {tolerant,lessfuzzy} %D \stopcombination %D \stoptyping \installcorenamespace {optimize} \installcommandhandler \??optimize {optimize} \??optimize \setupoptimize [\c!lines=\zerocount, \c!left=\zeropoint, \c!right=\zeropoint, \c!distance=\zeropoint] \permanent\protected\def\optimize[#S#1]% {\begingroup \ifhastok={#1}% \setupcurrentoptimize[#1]% \else \cdef\currentoptimize{#1}% \fi \scratchdimenone {\optimizeparameter\c!left }% \scratchdimentwo {\optimizeparameter\c!right}% \scratchcounterone{\optimizeparameter\c!lines}% \scratchdistance {\optimizeparameter\c!distance}% \normalexpanded {\endgroup \looseness\the\scratchcounterone\relax \emergencyextrastretch\the\scratchdistance\relax \ifzerodim\scratchdimenone\else \emergencyleftskip \zeropoint \s!plus \the\scratchdimenone\relax \fi \ifzerodim\scratchdimentwo\else \emergencyrightskip\zeropoint \s!plus \the\scratchdimentwo\relax \fi}% \ignorespaces} \defineoptimize[+\v!line][\c!lines=\plusone] \defineoptimize[-\v!line][\c!lines=\minusone] \defineoptimize[\v!flushleft ][\c!right=2\bodyfontsize] \defineoptimize[\v!flushright][\c!left=2\bodyfontsize] \defineoptimize[\v!normal ][\c!right=2\bodyfontsize,\c!distance=\bodyfontsize] \protect \endinput