Hi, Hans

I tried to run your first example, but ConTeXt throws an error and complains that \resetleftparbox was never defined.
Using version: 2021.11.13

Regards

Marcus Vinicius


On Thu, Oct 28, 2021 at 6:24 AM Hans Hagen via ntg-context <ntg-context@ntg.nl> wrote:
Hi,

Among the 'can they be made better' candidates in the engine are
\vadjust and \local[left|right]box primitives that are not really used
in context (okay, vadjust is used in mkii).

The \vadjust vertical injector can be illustrated with

\starttext
     \ignorespaces\input tufte \removeunwantedspaces
     we want a break before this line \vadjust pre {\break}%
     \ignorespaces\input tufte \removeunwantedspaces

     \page

     \ignorespaces\input tufte \removeunwantedspaces
     we want seperate lines now \leftparbox{\vadjust post {\break}}%
     \ignorespaces\input tufte \removeunwantedspaces
     \resetleftparbox{}
\stoptext

It's a signal that injects something in a vertical list without
interupting the horizontal text flow. One can inject before (pre) or
after (post which is default). New is that we can also influence the
order: after vs before preceding \vadjust in the same line.  Also new is
that deeply nested adjustments can migrate (so the hole los: marks,
inserts and vadjust are now in sync) which is demonstrated with the next
example:

\starttext
     \showstruts
     \input tufte \removeunwantedspaces\space
     \localleftbox  par {%
        \hbox to 0pt{%
           \llap{L}%
           \vadjust{\strut\blackrule[width=1cm,color=red]}%
           \hbox{\vadjust pre{\strut\blackrule[width=1cm,color=green]}}%
        }\hss
     }%
     \localrightbox par {}%
     \input tufte \removeunwantedspaces\space
     \vadjust pre    {\strut BEFORE 1}%
     \vadjust pre    {\strut BEFORE 2}%
     \vadjust before {\strut AFTER  1}%
     \vadjust before {\strut AFTER  2}%
     \ignorespaces
     \input tufte
\stoptext

Indeed it looks bad (ugly) but it illustrates the idea. What makes
vadjust sort of useless for content is that it messes up spacing (but if
there is real demand and usage i can sort that out at some point, maybe
some new options or so). Thsi example also brings us to local boxes:

\showframe

\starttext

\showmakeup[hbox]

\startnarrower[2*left] \raggedleft
{\localleftbox par {L1}\input tufte  \par}
\stopnarrower
\blank

\startnarrower[2*middle] \raggedcenter
{\localrightbox par {R1}\input tufte  \par}
\stopnarrower
\blank

\stoptext

New is the par keyword that forces the setting to be applied from the
first line downards (fyio: these commands, when display set registers,
when inline they set registers and inject a node). Watch out: one needs
to use grouping in order not to bleed into other mechanisms.

Also new is that we can query the content of these registers using \the,
as in:

\dorecurse{10}{
     \showboxes
     \localleftbox{\ruledhbox {\smallinfofont\setstrut\strut[L #1.0]}}%
     \localleftbox{\ruledhbox {\smallinfofont\setstrut\strut[L
#1.1]}\the\localleftbox}%
     \localleftbox{\ruledhbox {\smallinfofont\setstrut\strut[L
#1.2]}\the\localleftbox}%
     \localleftbox{\ruledhbox {\smallinfofont\setstrut\strut[L
#1.3]}\the\localleftbox}%
     %
     \localrightbox{\ruledhbox
{\smallinfofont\setstrut\strut[R #1.0]}}%

\localrightbox{\the\localrightbox\ruledhbox{\smallinfofont\setstrut\strut[R
#1.1]}}%

\localrightbox{\the\localrightbox\ruledhbox{\smallinfofont\setstrut\strut[R
#1.2]}}%
     \localrightbox{\the\localrightbox\ruledhbox{\smallinfofont[R #1.3]}}%
     % \localrightbox{}%
     \samplefile{tufte}
}

Flushing permits us to append and prepend but it's still ugly so that is
why we now have a new interface (context layer on top of engine):

\dorecurse{10}{
     \showboxes
     %
     \resetleftparbox
     \resetrightparbox
     %
     \prependleftparbox {\ruledhbox{\smallinfofont\setstrut\strut[L #1.0]}}%
     \prependleftparbox {\ruledhbox{\smallinfofont\setstrut\strut[L #1.1]}}%
     \prependleftparbox {\ruledhbox{\smallinfofont\setstrut\strut[L #1.2]}}%
     \prependleftparbox {\ruledhbox{\smallinfofont\setstrut\strut[L #1.3]}}%
     %
     \appendrightparbox{\ruledhbox{\smallinfofont\setstrut\strut[R #1.0]}}%
     \appendrightparbox{\ruledhbox{\smallinfofont\setstrut\strut[R #1.1]}}%
     \appendrightparbox{\ruledhbox{\smallinfofont\setstrut\strut[R #1.2]}}%
     \appendrightparbox{\ruledhbox{\smallinfofont[R #1.3]}}%
     %
     \samplefile{tufte}
}

But as this is not really user friendly, there is more: a mechanism for
hooking in handlers.

\definelocalboxes
   [linenumber]
   [command=\LeftNumber,
    location=left,
    width=3em,
    style=\bs,
    color=darkred]

\definelocalboxes
   [linenumbertwo]
   [linenumber]
   [command=\RightNumber,
    location=right,
    width=6em,
    style=\bf,
    color=darkgreen]

\definelocalboxes
   [linetext]
   [command=\LeftText,
    location=lefttext,
    style=\bs,
    color=darkblue]

\definelocalboxes
   [linetexttwo]
   [linetext]
   [command=\RightText,
    location=righttext,
    style=\bf,
    color=darkgray]

% just using the content

% \protected\def\LeftNumber {\hbox to
\localboxesparameter{width}{\strut\box\localboxcontentbox\hss)}}
% \protected\def\RightNumber{\hbox to
\localboxesparameter{width}{\strut(\hss\box\localboxcontentbox)}}

% using the provided line number:

% \def\LineNumberL{\the\localboxlinenumber}
% \def\LineNumberR{\the\localboxlinenumber}

% using a tex counter

% \newcount\MyLineNumberL
% \newcount\MyLineNumberR
% \def\LineNumberL{\global\advance\MyLineNumberL\plusone\the\MyLineNumberL}
% \def\LineNumberR{\global\advance\MyLineNumberR\plusone\the\MyLineNumberR}

% using proper counters

\definecounter[MyLineNumberL]
\definecounter[MyLineNumberR]

\setupcounter[MyLineNumberL][numberconversion=characters]
\setupcounter[MyLineNumberR][numberconversion=romannumerals]

\def\LineNumberL{\incrementcounter[MyLineNumberL]\convertedcounter[MyLineNumberL]}
\def\LineNumberR{\incrementcounter[MyLineNumberR]\convertedcounter[MyLineNumberR]}

\protected\def\LeftNumber {\hbox to
\localboxesparameter{width}{\strut(\LineNumberL\hss)}}
\protected\def\RightNumber{\hbox to
\localboxesparameter{width}{\strut(\hss\LineNumberR)}}

\protected\def\LeftText #1{#1\quad}
\protected\def\RightText#1{\quad#1}

\showframe

\starttext

\start
     \localbox[linenumber]{}%
     \localbox[linenumbertwo]{}%
     \localbox[linetext]{L}%
     \startlocalbox[linetexttwo]
         R
     \stoplocalbox
     \dorecurse{100}{
         \samplefile{tufte}
         \par
     }
\stop

If you play a bit with these low level mechanism the luametatex /
context combination now permits weird applications (which for sure some
of you will (ab)use). The above example shows how to implement line
numbers (there are drawbacks compared to the existing mechanisms) and
other stuff in the margins and text edges but the most important aspect
is that when the content in these boxes has width, it will be taken into
account in the par builder because that is what this is about: these
local boxes are taken into acount when breaking lines. When the handlers
kick in, you have

\localboxattribute         : more for internal use
\localboxlinenumber        : as the par builder sees it
\localboxwidth             : the local box width
\localboxoffset            : the total distance to the edge
\localboxleftskip          : the effective leftskip
\localboxrightskip         : the effective rightskip
\localboxlefthang          : the current shape related value
\localboxrighthang         : the current shape related value
\localboxindent            : only first line
\localboxparfillleftskip   : effective value (onky last line)
\localboxparfillrightskip  : effective value (only last line)
\localboxovershoot         : overfull compensation

most of these relate to normalized lines and as such there is plenty to
play with. Others can be seen in the examples.

I might add some more control to both these 'injection' mechanism
because directly out of the (pdftex/omega/luatex) they are not that
useful (which is probably also why we don't use them.) These are cheap
extensions so they don't really influence runtime much, so .. when not
used ... no harm done. I really have no clue how useful this is.

I need to ponder this usage:

\definelocalboxes
   [linetextA]
   [command=\LeftTextA,
    location=lefttext,
    style=\bs,
    color=darkblue]

\protected\def\LeftTextA#1{\llap{#1}\quad}

\definelocalboxes
   [linetextB]
   [command=\LeftTextB,
    location=left,
    style=\bs,
    color=darkgreen]

\protected\def\LeftTextB{\llap{\unhbox\localboxcontentbox}\quad}

\starttext

\dorecurse{10}{some text #1 }
\leftparbox {\red \bf keyword}HERE\leftparbox{}
\dorecurse{10}{some text #1 }
\blank

{\dorecurse{10}{some text #1 }
\leftparbox {\red \bf keyword}test
\dorecurse{10}{some text #1 }}
\blank

{\dorecurse{10}{some text #1 }
\localbox[linetextA]{keyword}HERE
\dorecurse{10}{some text #1 }}

{\dorecurse{10}{some text #1 }
\localbox[linetextB]{keyword}HERE
\dorecurse{10}{some text #1 }}

{\dorecurse{10}{some text #1 }
\localbox[linetextB]{keyword 1}HERE1
\dorecurse{10}{some text #1 }
\localbox[linetextB]{keyword 2}HERE2
\dorecurse{10}{some text #1 }}

\stoptext

so there's always so echallenge left.

Hans

-----------------------------------------------------------------
                                           Hans Hagen | PRAGMA ADE
               Ridderstraat 27 | 8061 GH Hasselt | The Netherlands
        tel: 038 477 53 69 | www.pragma-ade.nl | www.pragma-pod.nl
-----------------------------------------------------------------
___________________________________________________________________________________
If your question is of interest to others as well, please add an entry to the Wiki!

maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
webpage  : http://www.pragma-ade.nl / http://context.aanhet.net
archive  : https://bitbucket.org/phg/context-mirror/commits/
wiki     : http://contextgarden.net
___________________________________________________________________________________


--
Todas as coisas fatigam o corpo, salvo a música, que não fatiga nem o corpo nem seus membros, por ser descanso da alma, primavera do coração, distração do aflito, entretenimento do solitário, e viático do viajante.

Kunnâsh al-Hâ'ik (Cancioneiro de al-Hâ'ik)