%D \module %D [ file=strc-not, %D version=2008.10.20, %D title=\CONTEXT\ Structure Macros, %D subtitle=Note Handling, %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 Structure Macros / Note Handling} \registerctxluafile{strc-not}{autosuffix} \unprotect % todo: finish local rendering % todo: more p_strc_notations_* (outside trial loop) % todo: see if we can now use \insertpenalties (>0 == some left) \ifdefined\dotagsetnotesymbol \else \aliased\let\dotagsetnotesymbol\relax \fi \ifdefined\dotagsetnotation \else \aliased\let\dotagsetnotation \relax \fi %D \LMTX\ testcase: %D %D \starttyping %D \hbox {\hbox{\footnote{HH1}\footnote{HH2}}} \par %D \hbox {\hbox{x\footnote{XHH1}x\footnote{XHH2}}} \par %D \vbox {\setbox0\hbox{\footnote{VH1}\footnote{VH2}}\box0} \par %D \vbox {\hbox{\footnote{VH1}xxx\footnote{VH2}}} \par %D \vbox {\hbox{\footnote{VH1}\footnote{VH2}} %D \hbox{\footnote{VH1}\footnote{VH2}}} \par %D \vbox {\hbox{x\footnote{XVH1}x\footnote{XVH2}}} \par %D \vbox {\vbox{\footnote{VV1}\footnote{VV2}}} \par % two lines %D \vbox {\vbox{x\footnote{XVV1}x\footnote{XVV2}}} \par %D \stoptyping %D Notes have two handlers: notations and notes. Although notations can be defined %D independently it makes not much sense. In principle we can treat notes as lists %D but they are currently done as a variant on enumerations. I will provide a list %D variant as well. One complication is that for page related notes inserts are used %D and therefore notes are typeset immediately and descriptions are better suited %D for that. For instance endnotes can as well be typeset using lists. % textcommand/textstyle/textcolor : set by note commandhandler and used for inline number %D \macros %D {setupnote,setupnotation} %D %D We can influence footnote typesetting with the setup command: %D %D \showsetup{setupnotation} %D \showsetup{setupnote} %D %D The definition command indicate that we can frame the footnote area. The %D footnotes themselves are treated as descriptions. %D %D \showsetup{definenote} %D %D It's sort of a custom to precede footnotes by a horizontal rule and although %D fancy rules like %D %D \starttyping %D \hbox to 10em{\hskip-3em\dotfill} %D \stoptyping %D %D Are quite ligitimate, we default to a simple one 20\% of the text width. % \c!headstyle=\noteparameter\c!style, % \c!headcolor=\noteparameter\c!color, \installcorenamespace{notation} \installcommandhandler \??notation {notation} \??notation \installcounterassociation{notation} \aliased\let\setupnotations\setupnotation \definesymbol[\v!note:\v!previouspage][\llap{\low{\symbol[\v!previouspage]}}] \definesymbol[\v!note:\v!nextpage ][\llap{\low{\symbol[\v!nextpage ]}}] \setupnotations % check with old [\c!alternative=\v!note, %\c!headstyle=, %\c!titlestyle=, %\c!style=, %\c!color=, %\c!headcolor=, %\c!titlecolor=, \c!numbercommand=\high, %\c!symbolcommand=\lowllap, % experiment %\c!indicator=\v!no, % was \v!yes in mkii for page notes \c!width=\v!fit, \c!titledistance=.5em, \c!distance=.5em, %\c!hang=, %\c!sample=, %\c!align=, %\c!headalign=, \c!margin=\v!no, \c!before=, \c!inbetween=, \c!after=, \c!indentnext=\v!yes, \c!indenting=\v!never, \c!titleleft=(, \c!titleright=), %\c!closesymbol=, \c!closecommand=\wordright, \c!display=\v!yes, %\c!command=, \c!titlecommand=, \c!expansion=\v!no, %\c!xmlsetup=, %\s!catcodes=, \c!way=\v!by\v!text, \c!prefix=\v!no, \c!prefixconnector=., %\c!starter=, %\c!stopper=, \c!number=\v!yes, \c!text=, \c!start=0, \c!state=\v!start, \c!levels=3] %D The code here is mostly the same as enumerations but we want to keep them %D isolated and at some point we might differentiate. % \installcorenamespace{noteclass} \protected\def\strc_define_commands_notation#tag#level#parent% {\doifelsenothing{#parent} {\normalexpanded{\defineconstruction[#tag][\s!handler=\v!notation,\c!level=#level]}% \edefcsname\??notation#tag:\s!parent\endcsname{\??notation}}% {\normalexpanded{\defineconstruction[#tag][#parent][\s!handler=\v!notation,\c!level=#level]}% \edefcsname\??note #tag:\s!parent\endcsname{\??note#parent}% see later for \s!note \edefcsname\??notation#tag:\s!parent\endcsname{\??notation#parent}}% \instance\protected\edefcsname\e!next #tag\endcsname{\strc_notations_next{#tag}{\number#level}}% obsolete \instance\protected\edefcsname\c!reset#tag\endcsname{\strc_notations_reset{#tag}{\number#level}}% obsolete \instance\protected\edefcsname #tag\endcsname{\strc_notations_command[#tag]}% \instance\protected\edefcsname\e!start#tag\endcsname{\strc_notations_start[#tag]}% \instance\protected\edefcsname\e!stop #tag\endcsname{\strc_notations_stop}} \lettonothing\m_strc_notation_sub \appendtoks \lettonothing\m_strc_notation_sub \ifempty\currentnotationparent % clone => parent | subclone => clone | subsubclone => subclone \strc_define_commands_notation {\m_strc_notation_sub\currentnotation}% \plusone \empty \edef\p_levels{\notationparameter\c!levels}% \dostepwiserecurse\plustwo\p_levels\plusone {\strc_define_commands_notation {\v!sub\m_strc_notation_sub\currentnotation}% \recurselevel {\m_strc_notation_sub\currentnotation}% \edef\m_strc_notation_sub{\v!sub\m_strc_notation_sub}}% \definelist[\currentnotation]% goodie \else % clone => parent | subclone => subparent | subsubclone => subsubparent \edef\p_levels{\notationparameter\c!levels}% \dorecurse\p_levels {\strc_define_commands_notation {\m_strc_notation_sub\currentnotation}% \recurselevel {\m_strc_notation_sub\currentnotationparent}% \edef\m_strc_notation_sub{\v!sub\m_strc_notation_sub}}% \definelist[\currentnotation][\currentnotationparent]% goodie \fi \edef\p_counter{\notationparameter\s!counter}% can inherit from parent \ifempty\p_counter \let\p_counter\currentnotation \fi \doifelsecounter\p_counter\donothing{\strc_notes_define_counter\p_counter}% \letnotationparameter\s!counter\p_counter %\strc_notes_setup_counter\currentnotation \to \everydefinenotation \lettonothing\p_strc_constructions_title \lettonothing\p_strc_constructions_number \protected\defcsname\??constructioninitializer\v!notation\endcsname {\let \currentnotation \currentconstruction \enforced\let\constructionparameter \notationparameter \enforced\let\constructionnamespace \??notation \enforced\let\detokenizedconstructionparameter\detokenizednotationparameter \enforced\let\letconstructionparameter \letnotationparameter \enforced\let\useconstructionstyleandcolor \usenotationstyleandcolor \enforced\let\setupcurrentconstruction \setupcurrentnotation \edef\p_strc_constructions_number{\constructionparameter\c!number}% \ifx\p_strc_constructions_number\v!yes \settrue\c_strc_constructions_number_state \iftrialtypesetting \strc_counters_save\currentconstructionnumber \fi %\strc_counters_increment_sub\currentconstructionnumber\currentconstructionlevel \else \setfalse\c_strc_constructions_number_state \fi \edef\p_strc_constructions_title{\constructionparameter\c!title}% \ifx\p_strc_constructions_title\v!yes \settrue\c_strc_constructions_title_state \else \setfalse\c_strc_constructions_title_state \fi} \protected\defcsname\??constructionfinalizer\v!notation\endcsname {\ifconditional\c_strc_constructions_number_state \iftrialtypesetting \strc_counters_restore\currentconstructionnumber \fi \fi} %D Notations (we simply needed a word that relates to notes and is and sounds like %D description and enumeration) are a special case in the sense that they are %D stored, rendered elsewhere and referered to from where they are specified. For %D that reason they have a different set op main commands. % \notation[ref]{title} % \notation[reference=,title=] % \startnotation[ref] title \stopnotation \protected\def\strc_notations_next {\strc_constructions_next_indeed \namednotationparameter} % #1#2 \protected\def\strc_notations_reset{\strc_constructions_reset_indeed\namednotationparameter} % #1#2 %protected\def\strc_notations_set {\strc_constructions_set_indeed \namednotationparameter} % #1#2 \newconditional\c_strc_notations_anchored_next \def\strc_notations_finalize {\ifconditional\c_strc_notations_anchored_next \expandafter\strc_notations_finalize_next \else \expandafter\strc_notations_finalize_previous \fi} \def\strc_notations_finalize_previous {\normalexpanded{\endgroup\noteparameter\c!next}} \def\strc_notations_finalize_next {\endgroup\ignorespaces} \tolerant\protected\def\strc_notations_command[#1]#*[#2]% {\begingroup \edef\currentnote{#1}% \strc_constructions_initialize{#1}% \strc_notes_synchronize \edef\p_next{\noteparameter\c!anchor}% \ifx\p_next\v!next % for now only two states \settrue \c_strc_notations_anchored_next \else \setfalse\c_strc_notations_anchored_next \fi \ifnotesenabled \strc_counters_increment_sub\currentconstructionnumber\currentconstructionlevel \fi \ifhastok={#2}% \expandafter\strc_notations_command_setups \else \expandafter\strc_notations_command_reference \fi[#2]} \def\strc_notations_command_setups[#1]% {\strc_constructions_register[][\c!label={\descriptionparameter\c!text},\c!reference=,\c!title=,\c!bookmark=,\c!list=,\c!referencetext=,#1]% \strc_notations_wrapup} \tolerant\def\strc_notations_command_reference[#1]#*#=% {\strc_constructions_register[][\c!label={\descriptionparameter\c!text},\c!reference={#1},\c!title={#2},\c!bookmark=,\c!list=,\c!referencetext=]% \strc_notations_wrapup} \def\strc_notations_wrapup {\csname\??constructionnotehandler\currentconstructionhandler\endcsname \strc_constructions_finalize \strc_notations_finalize} \tolerant\protected\def\strc_notations_start {\strc_notations_start_indeed{\csname\e!stop\currentnotation\endcsname}} \tolerant\protected\defcsname\e!start\e!namednotation\endcsname {\strc_notations_start_indeed{\csname\e!stop\e!namednotation\endcsname}} \ifdefined\startnamednotation % we're in the english interface \else \tolerant\protected\def\startnamednotation {\strc_notations_start_indeed\stopnamednotation} \fi \tolerant\protected\def\strc_notations_start_indeed#1#*[#2]#*[#3]% {\begingroup \edef\currentnote{#2}% \strc_constructions_initialize{#2}% \strc_notes_synchronize \ifnotesenabled \strc_counters_increment_sub\currentconstructionnumber\currentconstructionlevel \fi \ifhastok={#3}% \expandafter\strc_notations_start_setups \else \expandafter\strc_notations_start_reference \fi#1[#3]} \let\strc_notations_pickup_yes\relax \protected\def\strc_notations_start_setups#1[#2]% {\normalexpanded{\def\noexpand\strc_notations_pickup_yes##/#1{\strc_notations_start_setups_indeed[#2]{##1}}}% \strc_notations_pickup_yes} \protected\def\strc_notations_start_setups_indeed[#1]#*#2% {\strc_constructions_register[][\c!label={\descriptionparameter\c!text},\c!reference=,\c!title={#2},\c!bookmark=,\c!list=,\c!referencetext=,#1]% \strc_notations_wrapup} \protected\def\strc_notations_start_reference#1[#2]% {\normalexpanded{\def\noexpand\strc_notations_pickup_yes##/#1{\strc_notations_start_reference_indeed[#2]{##1}}}% \strc_notations_pickup_yes} \protected\def\strc_notations_start_reference_indeed[#1]#*#2% {\strc_constructions_register[][\c!label={\descriptionparameter\c!text},\c!reference={#1},\c!title={#2},\c!bookmark=,\c!list=,\c!referencetext=]% \strc_notations_wrapup} \protected\def\strc_notations_stop {} %D A complication is that we need to set up rather specific properties of e.g. %D footnotes. It is for this reason that we introduce an extra level of %D indirectness. This way notations don't bark on undefined macros when used in %D combination. \protected\defcsname\??constructionnotehandler\v!notation\endcsname {\csname\??constructionnotehandler\currentconstructionhandler:\constructionparameter\c!type\endcsname} \protected\defcsname\??constructionnotehandler\v!notation:\endcsname % empty case {[\currentconstructionhandler:\currentconstruction]} %D Here is a simple renderer for notes \defineconstructionalternative [\v!note] [\c!renderingsetup=\??constructionrenderings:\v!note] \startsetups[\??constructionrenderings:\v!note] \noindent \leftboundary % experiment, to be done in more places \llap{\box\constructionheadbox\hskip\constructionparameter\c!distance}% \useconstructionstyleandcolor\c!style\c!color \ignorespaces \stopsetups %D We now implement the note definer. \installcorenamespace{note} \installframedcommandhandler \??note {note} \??note \let\setupnotes\setupnote % These only concern the inline symbol/number and wrapping of the whole list. \setupnotes % not all make sense here [\c!location=\v!page, %\c!conversion=, \c!rule=\v!on, \c!before=\blank, \c!bodyfont=\v!small, \c!anchor=, % can also be v!next %\c!style=, %\c!color=, %\c!after=, %\c!rulecolor=, %\c!rulecommand=, \c!rulethickness=\linewidth, \c!frame=\v!off, \c!distance=.125em, % in the text between symbols % \c!textseparator={,}, % optional separator \c!columndistance=1em, % \c!margindistance=.5em, \c!align=, % also use instead of \c!tolerance \c!split=\v!tolerant, \c!width=\makeupwidth, % \ifdim\hsize<\makeupwidth\hsize\else\makeupwidth\fi \c!height=\textheight, \c!command=, % \noteparameter\c!numbercommand, % (command in enumeration) too messy, called twice \c!separator=,% \c!textcommand=\high, \c!textstyle=\tx, %\c!textcolor=, \c!interaction=\v!yes, %\c!factor=, %\c!scope=, % \v!text \v!page \c!prefixconnector=., %\c!next=\autoinsertnextspace, \c!prefix=\v!no, %\c!continue=\v!no, \c!paragraph=\v!no, \c!inbetween=\hskip\emwidth, \c!symbol=\mathematics{*}, \c!n=1] \setupnotes [\c!expansion=\v!no, \c!xmlsetup=, \s!catcodes=] %D Insertions are part of notes. % \installcorenamespace{noteinsertion} \permanent\def\currentnoteinsertion {\noteparameter\s!insert} \permanent\def\currentnoteinsertionnumber{\namedinsertionnumber{\noteparameter\s!insert}} \appendtoks \ifempty\currentnoteparent \doifelseinsertion\currentnote \donothing {\defineinsertion[\currentnote]% could be an option % \normalexpanded{\t_strc_notes{\the\t_strc_notes\noexpand\strc_notes_process_list{\currentnote}}}}% \xtoksapp\t_strc_notes{\noexpand\strc_notes_process_list{\currentnote}}}% \letnoteparameter\s!insert\currentnote \definenotation[\currentnote][\c!type=\v!note]% \else \setexpandednoteparameter\s!insert{\namednoteparameter\currentnoteparent\s!insert}% \definenotation[\currentnote][\currentnoteparent][\c!type=\v!note]% \fi \clf_definenote {\currentnote}% {insert}% \currentnoteinsertionnumber \relax \to \everydefinenote % maybe we will share this at some point: \def\strc_notes_define_counter#tag% todo: move inline {\definecounter[#tag]% \registerenumerationcounter{#tag}} \appendtoks \synchronizenotationcounters \to \everysetupnotation \appendtoks \synchronizenotationcounters \to \everydefinenotation % so far %letcsname\??constructionstarthandler \v!notation\expandafter\endcsname\csname\??constructionstarthandler \v!enumeration\endcsname \letcsname\??constructionstarthandler \v!notation\expandafter\endcsname\csname\??constructionstarthandler \v!construction\endcsname % no par mess \letcsname\??constructionstophandler \v!notation\expandafter\endcsname\csname\??constructionstophandler \v!enumeration \endcsname \letcsname\??constructioncommandhandler\v!notation\expandafter\endcsname\csname\??constructioncommandhandler\v!enumeration \endcsname \letcsname\??constructiontexthandler \v!notation\expandafter\endcsname\csname\??constructiontexthandler \v!enumeration \endcsname \protected\defcsname\??constructionmainhandler\v!notation\endcsname#following% {\iftrialtypesetting \else \begingroup \currentconstructionsynchronize \c_attr_destination\currentconstructionattribute\relax % todo, whole text \signalcharacter \endgroup \fi \ifconditional\c_strc_notes_flushed\else #following\relax \fi} \protected\defcsname\??constructionnotehandler\v!notation:\v!note\endcsname % in the running text {\ifnotesenabled % do be done elsewhere % %let\currentnote\currentconstructionmain \let\currentnote\currentconstruction % else wrong inheritance % \iftrialtypesetting \strc_notes_inject_dummy \else \begingroup \edef\currentnotenumber{\clf_storenote{\currentnote}\currentconstructionlistentry}% \settrue\processingnote \ifconditional\c_strc_notes_skip \glet\lastnotesymbol\strc_notes_inject_symbol_nop \else \iftypesettinglines % otherwise problems with \type {xxx} \ignorelines % makes footnotes work in \startlines ... \stoplines \fi \ifconditional\c_strc_notes_symbol \strc_notes_inject_symbol_yes \else \unskip\unskip \glet\lastnotesymbol\strc_notes_inject_symbol_yes \fi \fi \ifconditional\postponingnotes % todo: per note class \global\settrue\postponednote \orelse\ifconditional\inlocalnotes % todo: per note class \global\settrue\postponednote \orelse\ifconditional\c_strc_notes_flushed \handlenoteitself\currentnote\currentnotenumber \orelse\ifconditional\c_strc_notes_delayed % probably end notes \else \handlenoteinsert\currentnote\currentnotenumber % either an insert or just delayed \fi \endgroup \fi \fi \ifconditional\c_strc_notes_skip \global\setfalse\c_strc_notes_skip \else \boundary\noteboundary \fi} %D Interaction in notes is somewhat complex due to the way notes get flushed. In %D principle it is more or less the same as lists but where in lists we pack whole %D entries, in notes this doesn't happen. Okay, in retrospect we could have made %D descriptions lists but that will be a backward compatibility mess. At some point %D a completely new mechanism might show up, but not now. Also, as notes are inserts %D there is some extra mess to be kept in mind and it's easier to maintain two %D mechanisms than to combine too much. %D %D Interaction is also complicated because we want to provide several variants. For %D simple reference there is no need for anything special, as page references will %D do and we store them in the list anyway. But if we want a destination with %D dimensions we will use an additional destination because we can have only one %D with the same name and we always have the number as one. % interaction: % % all : text and number % number|yes: only number % text : only text % % \dogetsimple : injects \installcorenamespace{noteinteractioninline} \installcorenamespace{noteinteractiondisplay} \newconstant\a_strc_notes_symbol_reference \newconstant\a_strc_notes_number_reference \newconstant\a_strc_notes_text_reference \newconstant\a_strc_notes_text_destination \lettonothing\strc_notes_get_reference_attribute_symbol \lettonothing\strc_notes_get_destination_attribute_symbol \def\strc_notes_interaction_check_inline {\edef\p_interaction{\noteparameter\c!interaction}% \csname\??noteinteractioninline \ifcsname\??noteinteractioninline\p_interaction\endcsname\p_interaction\else\v!no\fi \endcsname} \def\strc_notes_interaction_check_display {\edef\p_interaction{\noteparameter\c!interaction}% \csname\??noteinteractiondisplay \ifcsname\??noteinteractiondisplay\p_interaction\endcsname\p_interaction\else\v!no\fi \endcsname} \mutable\let\currentnotenumber\!!zerocount \lettonothing\strc_notes_get_reference_attribute_symbol \lettonothing\strc_notes_get_destination_attribute_symbol \let\strc_notes_set_reference_attribute_number\donothing \let\strc_notes_set_reference_attribute_text \donothing \let\strc_notes_set_destination_attribute_text\donothing \let\strc_notes_set_style_color_inline \relax \let\strc_notes_set_style_color_display\relax % inline \let\m_strc_notes_internal\relax \def\strc_notes_prepare_inline_references_nop {\lettonothing\strc_notes_get_reference_attribute_symbol \lettonothing\strc_notes_get_destination_attribute_symbol \let\strc_notes_set_style_color_inline\strc_notes_set_style_color_inline_nop} \def\strc_notes_prepare_inline_references_yes {\edef\m_strc_notes_internal{\clf_noteinternal{\currentnote}\currentnotenumber}% \strc_references_set_simple_reference{*\m_strc_notes_internal}% destination \strc_references_get_simple_reference{internal(\m_strc_notes_internal)}% reference \edef\strc_notes_get_destination_attribute_symbol{attr\destinationattribute\currentdestinationattribute}% \edef\strc_notes_get_reference_attribute_symbol{attr\referenceattribute\currentreferenceattribute}% \let\strc_notes_set_style_color_inline\strc_notes_set_style_color_inline_yes} \letcsname\??noteinteractioninline\v!no \endcsname\strc_notes_prepare_inline_references_nop \letcsname\??noteinteractioninline\v!all \endcsname\strc_notes_prepare_inline_references_yes \letcsname\??noteinteractioninline\v!number\endcsname\strc_notes_prepare_inline_references_yes \letcsname\??noteinteractioninline\v!text \endcsname\strc_notes_prepare_inline_references_yes \letcsname\??noteinteractioninline\v!yes \endcsname\strc_notes_prepare_inline_references_yes % display (for 'all' we need unique text and number attributes so we resolve twice % as we otherwise don't get the number one which is lapped in the margin so we need % to explicitly visit it) \def\strc_notes_prepare_display_references_nop {\let\strc_notes_set_reference_attribute_number\donothing \let\strc_notes_set_reference_attribute_text\donothing \let\strc_notes_set_destination_attribute_text\donothing \let\strc_notes_set_style_color_display\strc_notes_set_style_color_display_nop} \def\strc_notes_prepare_display_references_yes_number {\edef\m_strc_notes_internal{\clf_noteinternal{\currentnote}\currentnotenumber}% \ifcase\m_strc_notes_internal\relax \strc_notes_prepare_display_references_nop \else \let\strc_notes_set_reference_attribute_text\donothing \strc_references_get_simple_reference{*\m_strc_notes_internal}% reference \edef\strc_notes_set_reference_attribute_number{\c_attr_reference\currentreferenceattribute}% \let\strc_notes_set_style_color_display\strc_notes_set_style_color_display_yes \fi} \def\strc_notes_prepare_display_references_yes_text {\edef\m_strc_notes_internal{\clf_noteinternal{\currentnote}\currentnotenumber}% \ifcase\m_strc_notes_internal\relax \strc_notes_prepare_display_references_nop \else \strc_references_get_simple_reference{*\m_strc_notes_internal}% reference \edef\strc_notes_set_reference_attribute_text{\c_attr_reference\currentreferenceattribute}% \let\strc_notes_set_reference_attribute_number\donothing \let\strc_notes_set_style_color_display\strc_notes_set_style_color_display_yes \fi} \def\strc_notes_prepare_display_references_yes_all {\edef\m_strc_notes_internal{\clf_noteinternal{\currentnote}\currentnotenumber}% \ifcase\m_strc_notes_internal\relax \strc_notes_prepare_display_references_nop \else \strc_references_get_simple_reference{*\m_strc_notes_internal}% reference \edef\strc_notes_set_reference_attribute_text{\c_attr_reference\currentreferenceattribute}% \strc_references_get_simple_reference{*\m_strc_notes_internal}% reference \edef\strc_notes_set_reference_attribute_number{\c_attr_reference\currentreferenceattribute}% \let\strc_notes_set_style_color_display\strc_notes_set_style_color_display_yes \fi} \letcsname\??noteinteractiondisplay\v!no \endcsname\strc_notes_prepare_display_references_nop \letcsname\??noteinteractiondisplay\v!all \endcsname\strc_notes_prepare_display_references_yes_all \letcsname\??noteinteractiondisplay\v!number\endcsname\strc_notes_prepare_display_references_yes_number \letcsname\??noteinteractiondisplay\v!text \endcsname\strc_notes_prepare_display_references_yes_text \letcsname\??noteinteractiondisplay\v!yes \endcsname\strc_notes_prepare_display_references_yes_number \mutable\let\strc_notes_set_style_color_inline_nop \usenotestyleandcolor \mutable\let\strc_notes_set_style_color_display_nop\usenotationstyleandcolor \protected\def\strc_notes_set_style_color_inline_yes#style#color% {\usenotestyleandcolor#style#color% \iflocation\strc_notes_set_style_color_special\fi} \protected\def\strc_notes_set_style_color_display_yes#style#color% {\usenotationstyleandcolor#style#color% \iflocation\strc_notes_set_style_color_special\fi} \def\strc_notes_set_style_color_special {\iftrialtypesetting % keep \orelse\ifempty\currentcolorparameter \scratchcounter\clf_notedeltapage{\currentnote}\currentnotenumber\relax % todo calculate once \setlocationcolorspecified\scratchcounter \fi} \defcsname\??constructiontexthandler\v!notation\endcsname {\begingroup % we need to retrigger the reference as otherwise it gets lost because we don't do nested % references with the same id ... maybe some day if we can figure out a nice heuristic ... % the problem is that normally it's no issue but here we lap into the margin, so maybe that's % a criterium % \strc_notes_interaction_check_display \strc_notes_set_reference_attribute_number \dotagsetnotation \strc_notes_set_style_color_display\c!headstyle\c!headcolor \strc_enumerations_text \endgroup} % in mkii the pointer only showed up in pagewise notes \protected\def\strc_notes_inject_pointer % todo calculate once {\ifcase\clf_notedeltapage{\currentnote}\currentnotenumber\relax\relax % unknown \or % same page \or \noteparameter\c!symbolcommand{\symbol[\v!note:\v!nextpage]}% \or \noteparameter\c!symbolcommand{\symbol[\v!note:\v!previouspage]}% \fi} \protected\def\strc_notes_inject_symbol_yes {\strc_notes_inject_symbol_indeed\conditionaltrue} \protected\def\strc_notes_inject_symbol_nop {\strc_notes_inject_symbol_indeed\conditionalfalse} \definemargindata [strc_notes_destination_margin] [\v!left] [\c!margin=\zeropoint, \c!width=\zeropoint, \c!style=, \c!color=] \protected\def\strc_notes_inject_symbol_indeed#synchronize% {\ifconditional\c_strc_notations_anchored_next\else \removeunwantedspaces \doifelseitalic\/\donothing % Charles IV \footnote{the fourth} \fi \ifnum\lastboundary=\noteboundary \unboundary % \kern\noteparameter\c!distance % yes or no note font? or main text \strc_notes_inject_separator \fi \nobreak \begingroup \strc_notes_interaction_check_inline\strc_notes_set_style_color_inline\c!textstyle\c!textcolor \hbox \strc_notes_get_reference_attribute_symbol \strc_notes_get_destination_attribute_symbol \bgroup % \hbox \strc_notes_get_reference_attribute_symbol \bgroup \strc_notes_destination_hack \strc_references_flush_destination_nodes % a bit late but ok \dostarttagged\t!descriptionsymbol\currentnote \dotagsetnotesymbol \noteparameter\c!textcommand{\clf_noteprefixednumber{\currentnote}\currentnotenumber\relax}% % the next one can cycle so we need to make sure it has no advance width \doif{\noteparameter\c!indicator}\v!yes\strc_notes_inject_pointer \dostoptagged \egroup \endgroup \glettonothing\lastnotesymbol} \protected\def\strc_notes_inject_dummy % temp hack {\removeunwantedspaces \doifelseitalic\/\donothing % Charles IV \footnote{the fourth} \ifnum\lastboundary=\noteboundary \unboundary % \kern\noteparameter\c!distance % yes or no note font? or main text \strc_notes_inject_separator \fi \nobreak \hpack to .5\emwidth{}% \glettonothing\lastnotesymbol} \protected\def\strc_notes_inject_separator % patch by WS due to request on list {\edef\p_textseparator{\noteparameter\c!textseparator}% \ifempty\p_textseparator \kern\noteparameter\c!distance \else % skip or kern \nobreak \hbox\bgroup \usenotestyleandcolor\c!textstyle\c!textcolor \noteparameter\c!textcommand{\p_textseparator}% \kern\noteparameter\c!distance \egroup \nobreak \fi} % this needs a further cleanup ... soon as it's a slow mechanism % % -- set breakpoint in descriptions % -- reset after trialtypesetting % -- that way we can trick the symbol space % removed: % % \pushsomestates % % core-ins -> obsolete % % saveinsertiondata % restoreinsertiondata % saveinsertionbox % eraseinsertionbackup % restoreinsertionbackup % \def\savenotedata {} % \writestatus{todo}{save note data}} % \def\restorenotedata {} % \writestatus{todo}{restore note data}} % \def\savenotecontent {} % \writestatus{todo}{save note content}} % \def\restorenotecontent{} % \writestatus{todo}{restore note content}} % \def\erasenotebackup {} % \writestatus{todo}{erase note backup}} % page-set: % \def\enablenotes {\writestatus{todo}{enable notes}} % \def\disablenotes {\writestatus{todo}{disable notes}} % \def\savenotes {\writestatus{todo}{save notes}} % \def\flushsavednotes{\writestatus{todo}{flush notes}} % experiment: (compare scope=text and scope=page) % % \definenote[mynote][way=bytext,location=text,width=\leftmarginwidth,scope=page,rule=,before=,after=,factor=0] % \setuptexttexts[margin][\vbox to \textheight{\placenotes[mynote]\vfill}][] %D Footnotes are can be characterized by three components: %D %D \startitemize[packed] %D \item a small number \footnote {a footnote number} or symbol {\setupfootnotes %D [conversion=set 2]\footnote {a footnote}} %D \item and a similar mark at the bottom of the page %D \item followed by some additional text %D \stopitemize %D %D Because footnotes are declared at the location of their reference they can be %D seen as a special kind of floating bodies. Their placement is postponed but has %D to be taken into account in the pagebreak calculations. This kind of calculations %D are forced by using \type{\insert}s and dealing with all cases is not trivial. %D \macros %D {notesenabled} %D %D We need a couple of states because at some moments we don't want to mess around %D with inserts at all. Take for instance a table of contents. And so we can %D temporary disable footnotes by saying %D %D \starttyping %D \notesenabledfalse %D \stoptyping \newif\ifnotesenabled \notesenabledtrue % better mark a note .. once flushed no more flushing %appendtoks \notesenabledfalse \to \everymarking \appendtoks \notesenabledfalse \to \everybeforepagebody \appendtoks \notesenabledfalse \to \everystructurelist % quick hack \appendtoks \notesenabledfalse \to \everysimplifycommands % quick hack \appendtoks \notesenabledfalse \to \everypreroll % quick hack %D Often we need to process the whole set of notes and to make that fast, we use a %D token register: % we have several synchronizers: % % - after a definition % - after a specific setup % - after a general setup (inheritance of dimensions) % - just before a note is typeset \newtoks\t_strc_notes \let\strc_notes_process_list\gobbleoneargument \protected\def\strc_notes_process#action% argument is a \macro that uses \currentnote {\def\strc_notes_process_list##1{\edef\currentnote{##1}\let\currentdescription\currentnote#action}% \the\t_strc_notes} \newtoks\everychecknote % just before a note is typeset \newtoks\everysynchronizenote % after a general setup has happened \appendtoks \ifempty\currentnote \else \setupnotations[\currentnote][]% also a synchronize \fi \to \everysynchronizenote \def\strc_notes_synchronize {\the\everysynchronizenote} % we can speed this one up if needed by avoiding the commalist \appendtoks \strc_notes_process\strc_notes_synchronize \to \everysetupnoteroot \appendtoks \the\everysynchronizenote \to \everydefinenote % \starttext % text \startfootnote Test.\stopfootnote % test \footnote{xxxx} \subfootnote{xxxx} % test \footnote{xxxx} \subfootnote{xxxx} % \stoptext \installcorenamespace{notecommand} \installcorenamespace{notealign} \installcorenamespace{notepenalty} \installcorenamespace{noterule} \permanent\protected\def\currentnoterulecommand{\begincsname\??notecommand\currentnote\endcsname} \permanent\protected\def\currentnoterulealign {\begincsname\??notealign \currentnote\endcsname} \permanent\protected\def\currentnoterulecommandcommand{\noteparameter\c!rulecommand} \permanent\protected\def\currentnoterulecommandnormal {\normalnoterule} % no let as it can be changed afterwards \permanent\protected\def\letcurrentnoterulecommand{\enforced\letcsname\??notecommand\currentnote\endcsname} \permanent\protected\def\letcurrentnoterulealign {\enforced\letcsname\??notealign \currentnote\endcsname} \appendtoks \enforced\letcsname\??notecommand\currentnote\endcsname\currentnoterulecommandnormal \enforced\letcsname\??notealign \currentnote\endcsname\lefttoright \to \everysynchronizenote \def\strc_notes_set_rule {\letcurrentnoterulecommand\relax % so we default to nothing \letcurrentnoterulealign \relax \processcommacommand[\noteparameter\c!rule]\strc_notes_set_rule_step} \def\strc_notes_set_rule_step#alternative% {\begincsname\??noterule#alternative\endcsname} \def\strc_notes_set_rule_autodir {\doifelserighttoleftinbox\currentnoteinsertionnumber\righttoleft\lefttoright} \defcsname\??noterule \v!command\endcsname{\letcurrentnoterulecommand\currentnoterulecommandcommand} \defcsname\??noterule \v!on\endcsname{\letcurrentnoterulecommand\currentnoterulecommandnormal} \defcsname\??noterule \v!normal\endcsname{\letcurrentnoterulecommand\currentnoterulecommandnormal} \defcsname\??noterule \v!left\endcsname{\letcurrentnoterulecommand\currentnoterulecommandnormal \letcurrentnoterulealign \lefttoright} \defcsname\??noterule \v!right\endcsname{\letcurrentnoterulecommand\currentnoterulecommandnormal \letcurrentnoterulealign \righttoleft} \defcsname\??noterule\v!paragraph\endcsname{\letcurrentnoterulecommand\currentnoterulecommandnormal \letcurrentnoterulealign \strc_notes_set_rule_autodir} \defcsname\??noterule \v!off\endcsname{\letcurrentnoterulecommand\relax} \appendtoks \strc_notes_set_rule \to \everysynchronizenote \permanent\def\currentnotepenalty {\ifcsname\??notepenalty\noteparameter\c!split\endcsname \lastnamedcs \else \numexpr\noteparameter\c!split\relax \fi} \setnewconstant\notepenaltytolerant \zerocount \setnewconstant\notepenaltystrict 9999 \setnewconstant\notepenaltyverystrict\maxdimen \letcsname\??notepenalty\v!tolerant \endcsname\notepenaltytolerant \letcsname\??notepenalty\v!strict \endcsname\notepenaltystrict \letcsname\??notepenalty\v!verystrict\endcsname\notepenaltyverystrict \letcsname\??notepenalty \endcsname\notepenaltytolerant %D The following switch can be used to disable limiting the height of the footnote %D area, something that is needed in multi column balancing. Use this switch with %D care. \newif\ifnotelimit \notelimittrue % shared \def\strc_notes_set_factor {\edef\p_factor{\noteparameter\c!factor}% \ifempty\p_factor \else \ifnum\p_factor<\zerocount \else % \global \page_inserts_set_multiplier\currentnoteinsertionnumber\p_factor % new: global \fi \fi} \appendtoks \strc_notes_set_factor \to \everysynchronizenote % locations: \installcorenamespace{notelocationvariant} \installcorenamespace{notepositionvariant} \installcorenamespace{notedelayedvariant} \installcorenamespace{notelocation} \newconditional\c_strc_notes_delayed \newconditional\c_strc_notes_flushed \protected\def\strc_notes_set_delayed_yes{\settrue \c_strc_notes_delayed\setfalse\c_strc_notes_flushed} \protected\def\strc_notes_set_delayed_nop{\setfalse\c_strc_notes_delayed\setfalse\c_strc_notes_flushed} \protected\def\strc_notes_set_delayed_lst{\settrue \c_strc_notes_delayed\settrue \c_strc_notes_flushed} \defcsname\??notelocation\v!page\endcsname {\letcsname\??notedelayedvariant \currentnote\endcsname\strc_notes_set_delayed_nop \letcsname\??notelocationvariant\currentnote\endcsname\strc_notes_set_location_page} \defcsname\??notelocation\v!columns\endcsname {\letcsname\??notedelayedvariant \currentnote\endcsname\strc_notes_set_delayed_nop \letcsname\??notelocationvariant\currentnote\endcsname\strc_notes_set_location_columns} \defcsname\??notelocation\v!lastcolumn\endcsname {\letcsname\??notedelayedvariant \currentnote\endcsname\strc_notes_set_delayed_nop \letcsname\??notelocationvariant\currentnote\endcsname\strc_notes_set_location_lastcolumn} \defcsname\??notelocation\v!firstcolumn\endcsname {\letcsname\??notedelayedvariant \currentnote\endcsname\strc_notes_set_delayed_nop \letcsname\??notelocationvariant\currentnote\endcsname\strc_notes_set_location_firstcolumn} \defcsname\??notelocation\v!none\endcsname {\letcsname\??notedelayedvariant \currentnote\endcsname\strc_notes_set_delayed_yes \letcsname\??notelocationvariant\currentnote\endcsname\strc_notes_set_location_none} \defcsname\??notelocation\v!list\endcsname {\letcsname\??notedelayedvariant \currentnote\endcsname\strc_notes_set_delayed_lst \letcsname\??notelocationvariant\currentnote\endcsname\strc_notes_set_location_none} \defcsname\??notelocation\v!text\endcsname {\letcsname\??notedelayedvariant \currentnote\endcsname\strc_notes_set_delayed_yes \letcsname\??notelocationvariant\currentnote\endcsname\strc_notes_set_location_text} \defcsname\??notelocation\v!high\endcsname {\letcsname\??notepositionvariant\currentnote\endcsname\strc_notes_set_position_high} \defcsname\??notelocation\v!bottom\endcsname {\letcsname\??notepositionvariant\currentnote\endcsname\strc_notes_set_position_bottom} \defcsname\??notedelayedvariant \??notedelayedvariant \endcsname{\strc_notes_set_delayed_nop } % not \let \defcsname\??notepositionvariant\??notepositionvariant\endcsname{\strc_notes_set_position_bottom} % not \let \defcsname\??notelocationvariant\??notelocationvariant\endcsname{\strc_notes_set_location_page } % not \let \protected\def\strc_notes_set_delayed {\csname\??notedelayedvariant \ifcsname\??notedelayedvariant\currentnote\endcsname \currentnote \else \??notedelayedvariant \fi \endcsname} \protected\def\strc_notes_set_position {\csname\??notepositionvariant \ifcsname\??notepositionvariant\currentnote\endcsname \currentnote \else \??notepositionvariant \fi \endcsname} \protected\def\strc_notes_set_location {\csname\??notelocationvariant \ifcsname\??notelocationvariant\currentnote\endcsname \currentnote \else \??notelocationvariant \fi \endcsname} \protected\def\strc_notes_set_variants {\normalexpanded{\rawprocesscommalist[\noteparameter\c!location]\strc_notes_set_location_step}} \protected\def\strc_notes_set_location_step#alternative% the insert related one {\begincsname\??notelocation#alternative\endcsname} \appendtoks \strc_notes_set_variants \strc_notes_set_delayed \to \everysynchronizenote \newskip \s_strc_notes_distance % we need to implement stretch \newcount\c_strc_notes_columns \newskip \s_strc_notes_before \newskip \s_strc_notes_inbetween \newconditional\c_strc_notes_first_flushed % we can store them per insert so so real need to redo it \appendtoks \edef\p_spacebefore{\rootnoteparameter\c!spacebefore}% \ifempty\p_spacebefore \global\s_strc_notes_before\zeropoint \else \setbox\scratchbox\vbox{\blank[\p_spacebefore]\global\s_strc_notes_before\lastskip}% \fi \edef\p_spaceinbetween{\noteparameter\c!spaceinbetween}% \ifempty\p_spaceinbetween \global\s_strc_notes_inbetween\zeropoint \else \setbox\scratchbox\vbox{\blank[\p_spaceinbetween]\global\s_strc_notes_inbetween\lastskip}% \fi \to \everysynchronizenote \def\strc_notes_set_distance {\begingroup \restoreglobalbodyfont \setbox\scratchbox\vbox % no reuse as it can mirror {\forgetall \dontcomplain \noteparameter\c!before \placenoterule \strut \noteparameter\c!after}% % also dp now \scratchdimen\dimexpr\htdp\scratchbox-\lineheight\relax \ifgridsnapping \getnoflines\scratchdimen \scratchdimen\noflines\lineheight \fi \expandafter\endgroup\expandafter \s_strc_notes_distance\the\scratchdimen\relax} \def\strc_notes_set_columns {\c_strc_notes_columns\noteparameter\c!n\relax \ifcase\c_strc_notes_columns \c_strc_notes_columns\plusone \fi} \def\strc_notes_set_location_page {\setfalse\c_strc_notes_delayed \strc_notes_set_distance \strc_notes_set_columns \page_inserts_set_location \currentnoteinsertion\v!page % \setupinsertion[\currentnote][\c!location=\v!page]% \page_inserts_set_multiplier\currentnoteinsertionnumber\numexpr(\plusthousand/\c_strc_notes_columns)*\nofmulticolumns\relax \page_inserts_set_limit \currentnoteinsertionnumber\ifnotelimit\dimexpr\noteparameter\c!height*\c_strc_notes_columns\relax\else\maxdimen\fi \page_inserts_set_distance \currentnoteinsertionnumber\s_strc_notes_distance} \def\strc_notes_set_location_columns {\setfalse\c_strc_notes_delayed \strc_notes_set_distance \strc_notes_set_columns % \ifnum\currentnofcolumns=\zerocount \ifnum\nofcolumns=\zerocount \c_strc_notes_columns\plusone \fi \page_inserts_set_location \currentnoteinsertion\v!columns % \setupinsertion[\currentnote][\c!location=\v!columns]% \page_inserts_set_multiplier\currentnoteinsertionnumber\numexpr\plusthousand/\c_strc_notes_columns\relax \page_inserts_set_limit \currentnoteinsertionnumber\ifnotelimit\dimexpr\noteparameter\c!height*\c_strc_notes_columns\relax\else\maxdimen\fi \page_inserts_set_distance \currentnoteinsertionnumber\s_strc_notes_distance} \def\strc_notes_set_location_somecolumn#whatcolumn% {\setfalse\c_strc_notes_delayed \strc_notes_set_distance \strc_notes_set_columns \page_inserts_set_location \currentnoteinsertion#whatcolumn% \setupinsertion[\currentnote][\c!location=#whatcolumn]% \page_inserts_set_multiplier\currentnoteinsertionnumber\plusthousand \page_inserts_set_limit \currentnoteinsertionnumber\ifnotelimit\noteparameter\c!height\else\maxdimen\fi \page_inserts_set_distance \currentnoteinsertionnumber\s_strc_notes_distance} \def\strc_notes_set_location_firstcolumn{\strc_notes_set_location_somecolumn\v!firstcolumn} \def\strc_notes_set_location_lastcolumn {\strc_notes_set_location_somecolumn\v!lastcolumn } \def\strc_notes_set_location_text % we don't use inserts anyway (e.g. endnotes) {\settrue\c_strc_notes_delayed \clf_setnotestate{\currentnote}{store}% \page_inserts_set_location \currentnoteinsertion\v!text % \setupinsertion[\currentnote][\c!location=\v!text]% \page_inserts_set_multiplier\currentnoteinsertionnumber\zerocount \page_inserts_set_limit \currentnoteinsertionnumber\maxdimen \page_inserts_set_distance \currentnoteinsertionnumber\zeropoint} \let\strc_notes_set_location_none\strc_notes_set_location_text \def\strc_notes_set_properties {\strc_notes_set_columns \strc_notes_set_distance \strc_notes_set_location \strc_notes_set_delayed} \let\strc_notes_set_position_high\relax \def\strc_notes_set_position_bottom {\settrue\c_notes_bottom_present} \appendtoks \strc_notes_set_properties \to \everysynchronizenote %D A fast checker for bottom notes being used: \newconditional\c_notes_bottom_present % \def\strc_notes_check_if_bottom_present_indeed % in otr ! % {\ifvoid\currentnoteinsertionnumber\else % \strc_notes_set_position % \fi} \def\strc_notes_check_if_bottom_present_indeed % in otr ! {\ifzeropt\page_inserts_get_height\currentnoteinsertionnumber\else \strc_notes_set_position \fi} \def\strc_notes_check_if_bottom_present_step {\ifconditional\c_notes_bottom_present\else\strc_notes_check_if_bottom_present_indeed\fi} \def\strc_notes_check_if_bottom_present {\setfalse\c_notes_bottom_present \strc_notes_process\strc_notes_check_if_bottom_present_step} % Example of using factor: % % \definenote[mynote][way=bypage,location=text,width=\marginwidth,rule=,before=,factor=0] % \setuplayout[backspace=5cm,margin=3cm,margindistance=.5cm,width=middle] % \setuptexttexts[margin][\vbox to \textheight{\placenotes[mynote]\vfill}][] % \starttext % \dorecurse{10}{test \mynote{one one one one one one} \input zapf \mynote{one one one one one one} } % \stoptext %D The noterule can be a graphic and therefore calling this setup macro at every %D skipswitch is tricky (many many MP runs). Let's just reserve a few points, that %D probably match those of the stretch component. A bit messy: \permanent\protected\def\placenoterule {\begingroup \currentnoterulealign \currentnoterulecommand \par \endgroup} \permanent\protected\def\normalnoterule {\ifvmode \dontleavehmode \blackrule [\c!color=\noteparameter\c!rulecolor, \c!width=.2\hsize, \c!height=\noteparameter\c!rulethickness, \c!depth=\zeropoint]% \endgraf \kern\strutdepth \fi} %D The formatting depends on the width of the table, so we have to set \type {n} to %D zero. %D %D \starttyping %D \startbuffer %D \bTABLE %D \bTR \bTD one \footnote{\dorecurse{10}{abcd }} \eTD \bTD two \eTD \eTR %D \bTR \bTD three fout five six seven eight nine \eTD \bTD ten \eTD \eTR %D \eTABLE %D \stopbuffer %D %D \startlocalfootnotes[n=0,location={text,none}] %D \placelegend[n=2]{\getbuffer}{\placelocalfootnotes} %D \stoplocalfootnotes %D \stoptyping %D \macros %D {footnote} %D %D A footnote can have a reference as optional argument and therefore its formal %D specification looks like: %D %D \showsetup{footnote} %D %D This command has one optional command: the reference. By saying \type{[-]} the %D number is omitted. The footnote command is not that sensitive to spacing, so it's %D quite legal to say: %D %D \startbuffer %D Users of \CONTEXT\ must keep both feet \footnote {Given they have two.} on the %D ground and not get confused \footnote {Or even crazy.} by all those obscure %D \footnote {But fortunately readable.} parameters. %D \stopbuffer %D %D \typebuffer %D %D When setting the \type{conversion} to \type{set 2} we get %D something like: %D %D \bgroup %D \startnarrower %D \setupfootnotes[conversion=set 1] %D \getbuffer %D \stopnarrower %D \egroup %D %D Typesetting footnotes is, at least for the moment, disabled when reshaping boxes. %D The additional macro \type {\footnotetext} and the associated \type {\note} macro %D were implemented at request of users on the mailing list and a suggestion by taco %D to split of the symbol placement. I decided to merge this functionality with the %D existing \type {\note} functionality. \newconditional\c_strc_notes_symbol \settrue\c_strc_notes_symbol % not used \newconditional\c_strc_notes_skip \permanent\protected\def\setnote [#tag]{\csname#tag\endcsname} \permanent\protected\def\setnotetext[#tag]{\global\settrue\c_strc_notes_skip\csname#tag\endcsname} \permanent\protected\def\handlenoteinsert#tag#id% {\begingroup \edef\currentnote{#tag}% \strc_constructions_initialize{#tag}% \strc_notes_synchronize \the\everybeforenoteinsert \insert\currentnoteinsertionnumber\bgroup \the\everyinsidenoteinsert\relax \usesetupsparameter\noteparameter % experimental \useinterlinespaceparameter\noteparameter \doifelse{\noteparameter\c!paragraph}\v!yes {\nointerlineskip \startvboxtohboxseparator \noteparameter\c!inbetween \stopvboxtohboxseparator \startvboxtohbox \handlenoteitself{#tag}{#id}% \stopvboxtohbox} {\handlenoteitself{#tag}{#id}}% \egroup \the\everyafternoteinsert \endgroup} \permanent\protected\def\betweennoteitself#tag% used ? {\edef\currentnote{#tag}% \doif{\noteparameter\c!paragraph}\v!yes{\noteparameter\c!inbetween}} \permanent\protected\def\handlenoteitself#tag#id% {\edef\currentnotenumber{#id}% \edef\currentnote{#tag}% \strc_constructions_initialize{#tag}% \strc_notes_synchronize \edef\currentconstructionlistentry{\clf_notelistindex{\currentnote}#id}% index in list cache % as we can have collected notes (e.g. in tables) we need to recover % \currentdescriptionattribute and \currentdescriptionsynchronize % \reinstatecachedconstructionnumberentry\currentconstructionlistentry % we could store the number in the entry (e.g. needed when local notes in table) % \dontcomplain %begingroup \strc_notes_interaction_check_display \strc_notes_set_reference_attribute_text \strc_constructions_stored_start \begstrut \strc_references_flush_destination_nodes \strc_notes_set_destination_attribute_text \ifconditional\c_strc_notes_flushed\else \strc_notes_inject_text\relax \fi \ifvmode\obeydepth\else\endstrut\fi % \obeydepth is new per 2015-01-10 \strc_constructions_stored_stop %endgroup } \protected\def\strc_notes_inject_text % hm main? {\clf_savedlisttitle{\currentconstructionmain}\currentconstructionlistentry\relax} \installstructurelistprocessor{construction}{\usestructurelistprocessor{section}} \newboundary\noteboundary \newconditional\processingnote \newconditional\postponednote \newtoks\everybeforenoteinsert \newtoks\everyinsidenoteinsert \newtoks\everyafternoteinsert \permanent\protected\def\doifelseinnote {\ifconditional\processingnote \expandafter\firstoftwoarguments \else \expandafter\secondoftwoarguments \fi} \appendtoks \enforced\lettonothing\flushnotes \enforced\lettonothing\postponenotes \forgetall \resetallattributes % new, we don't want color bleed into notes \inheritmaintextcolor % but we do want to obey the textcolor \to \everybeforenoteinsert \def\strc_notes_set_penalties {% stored in insert node \floatingpenalty \currentnotepenalty % now per note \page_inserts_set_penalty\currentnoteinsertionnumber\currentnotepenalty % used when typesetting \interlinepenalty\plushundred % plain value % used when we need to split in columns \ifnum\noteparameter\c!n>\plusone \penalty\zerocount % otherwise no split in columns, maybe just always (tex just adds it to accumulated) \fi} \appendtoks \strc_notes_set_penalties \forgetall % again \strc_notes_set_bodyfont \redoconvertfont % to undo \undo calls in in headings etc \splittopskip\strutht % not actually needed here \splitmaxdepth\strutdp % not actually needed here \page_inserts_set_maxdepth \currentnoteinsertionnumber\strutdp % % not: % % \leftmargindistance \noteparameter\c!margindistance % \rightmargindistance\leftmargindistance % \ifnum\noteparameter\c!n=\zerocount % no ifcase new 31-07-99 ; always ? % \doifnotinset{\noteparameter\c!width}{\v!fit,\v!broad}\setnotehsize % ? % \fi % \pickupattributes \to \everyinsidenoteinsert %D Nasty, the might be more: \appendtoks \strc_itemgroups_push \to \everybeforenoteinsert \appendtoks \strc_itemgroups_pop \to \everyafternoteinsert % maybe but better use [scope=local] here % % \appendtoks % \setfalse\inhibitmargindata % \to \everyinsidenoteinsert \setupnotes [\c!width=\v!auto] % \permanent\protected\def\setnotehsize % {\ifinsidemulticolumns % \setnoteparameter\c!width{\makeupwidth}% % \else % \edef\p_width{\noteparameter\c!width}% % \ifx\p_width\v!auto % % \ifinsidecolumns % \setnoteparameter\c!width{\ifdim\hsize<\makeupwidth\hsize\else\makeupwidth\fi}% % % \else % % \setnoteparameter\c!width{\makeupwidth}% % % \fi % \orelse\ifempty\p_width % \setnoteparameter\c!width{\hsize}% % \fi % \fi % \hsize\noteparameter\c!width\relax} % % We construct immediately and migrate so: \permanent\protected\def\setnotehsize {\edef\p_width{\noteparameter\c!width}% \ifx\p_width\v!auto % intercept old value \let\p_width\makeupwidth \setnoteparameter\c!width{\makeupwidth}% \fi \hsize\p_width\relax} \appendtoks % only needed when columns (could be three \set...) \setnotehsize \setsimplecolumnshsize[\c!distance=\noteparameter\c!columndistance,\c!n=\noteparameter\c!n,\c!width=\noteparameter\c!width]% \to \everyinsidenoteinsert %D Normally footnotes are saved as inserts that are called upon as soon as the %D pagebody is constructed. The footnote insertion routine looks just like the %D \PLAIN\ \TEX\ one, except that we check for the end note state. % testcase for split bottom alignment see (a) below % % \dorecurse{6}{\input tufte\footnote{\input ward \input tufte \relax}} \newconditional\c_strc_notes_first_placed \permanent\protected\def\placenoteinserts {\setfalse\c_strc_notes_first_placed \strc_notes_process\strc_notes_place_inserts} \def\strc_notes_place_inserts {\strc_notes_set_delayed % \strc_notes_synchronize % we need to know if it's delayed \ifconditional\c_strc_notes_delayed \else % \ifdim\ht\currentnoteinsertionnumber>\zeropoint % or a faster delayed test \ifcase\page_inserts_get_height\currentnoteinsertionnumber\else \strc_notes_place_inserts_indeed \settrue\c_strc_notes_first_placed \fi \fi} \def\strc_notes_place_inserts_indeed {\relax % \ifdim\ht\currentnoteinsertionnumber>\zeropoint \ifcase\page_inserts_get_height\currentnoteinsertionnumber\else \endgraf \ifvmode \whitespace \ifconditional\c_strc_notes_first_placed \edef\p_spaceinbetween{\noteparameter\c!spaceinbetween}% \ifempty\p_spaceinbetween\else \blank[\p_spaceinbetween]% \fi \else \edef\p_spacebefore{\rootnoteparameter\c!spacebefore}% \ifempty\p_spacebefore\else \blank[\p_spacebefore]% \fi \fi \noteparameter\c!before \fi \placenoterule \bgroup \strc_notes_set_bodyfont \setbox\scratchbox\hbox {\strc_notes_flush_inserts}% \page_postprocessors_linenumbers_deepbox\scratchbox \setbox\scratchbox\hbox {\setupcurrentnote [\c!location=, \c!width=\v!fit, \c!height=\v!fit, \c!strut=\v!no, \c!offset=\v!overlay]% \inheritednoteframed {\ifzeropt\dp\scratchbox % this hack is needed because \vadjust \hpack{\lower\strutdp\box\scratchbox}% % in margin number placement \else % hides the (always) present depth \box\scratchbox \fi}}% \setbox\scratchbox\hpack{\lower\strutdepth\box\scratchbox}% \dp\scratchbox\strutdepth % so we know that it has the note bodyfont depth \ifvmode \nointerlineskip % else sometimes empty line \fi \box\scratchbox \egroup \endgraf \ifvmode \noteparameter\c!after \fi \fi} \def\strc_notes_flush_inserts {\ifcase\noteparameter\c!n\relax % should not happen \or \strc_notes_flush_inserts_normal \else \strc_notes_flush_inserts_columns \fi} \def\strc_notes_flush_inserts_normal {\strc_notes_flush_global \obeydepth} % (a) added , since split footnotes will not align properly \def\strc_notes_flush_inserts_columns {\begingroup \setnotehsize % probably still not ok for columns \startsimplecolumns[\c!distance=\noteparameter\c!columndistance,\c!n=\noteparameter\c!n,\c!width=\noteparameter\c!width]% \strc_notes_flush_global \stopsimplecolumns \endgroup} % idea: tag with attr and then just flush them again \def\strc_notes_flush_global {\begingroup \useinterlinespaceparameter\noteparameter \doifelse{\noteparameter\c!paragraph}\v!yes {\leftorrightvbox % cf mail from ws to list {\starthboxestohbox \iftrialtypesetting \page_inserts_get_uncopied \else \page_inserts_get_unboxed \fi \currentnoteinsertionnumber \stophboxestohbox}} {\iftrialtypesetting \ifvmode\page_inserts_get_uncopied\else\page_inserts_get_copied\fi \else \ifvmode\page_inserts_get_unboxed \else\page_inserts_get_boxed \fi \fi \currentnoteinsertionnumber}% \endgroup} %D Supporting end notes is surprisingly easy. Even better, we can combine this %D feature with solving the common \TEX\ problem of disappearing inserts when %D they're called for in deeply nested boxes. The general case looks like: %D %D \starttyping %D \postponenotes %D \.box{whatever we want with footnotes} %D \flushnotes %D \stoptyping %D %D This alternative can be used in headings, captions, tables etc. The latter one %D sometimes calls for notes local to the table, which can be realized by saying %D %D \starttyping %D \setlocalfootnotes %D some kind of table with local footnotes %D \placelocalfootnotes %D \stoptyping %D %D Postponing is accomplished by simply redefining the (local) insert operation. A %D not too robust method uses the \type{\insert} primitive when possible. This %D method fails in situations where it's not entirely clear in what mode \TEX\ is. %D Therefore the auto method can is to be overruled when needed. \newconditional\postponingnotes % we need a proper state: normal, postponing, flushing \permanent\protected\def\postponenotes % will be locally overloaded {\ifcase\insertionmigrationmode \ifconditional\postponingnotes\else \global\settrue\postponingnotes \enforced\glet\flushnotes\doflushnotes \clf_postponenotes \fi \fi} \permanent\lettonothing\flushnotes % also \ifcase\insertionmigrationmode here, needs testing: \permanent\protected\def\startpostponingnotes % experimental, page-mix {\ifconditional\postponingnotes\else \global\settrue\postponingnotes %\glet\flushnotes\doflushnotes \clf_postponenotes \fi} \permanent\protected\def\stoppostponingnotes % experimental, page-mix {\doflushnotes} \permanent\protected\def\doflushnotes {\ifconditional\postponingnotes \begingroup \enforced\lettonothing\flushnotes \enforced\lettonothing\postponenotes \ifconditional\postponednote \ifhmode % needed for tagging ... otherwise we get some weird node free error \signalcharacter \fi \fi \clf_flushpostponednotes% this also resets the states ! \global\setfalse\postponednote \global\setfalse\postponingnotes \enforced\glettonothing\flushnotes \endgroup \fi} %D \macros %D {startlocalfootnotes,placelocalfootnotes} %D %D The next two macros can be used in for instance tables, as we'll demonstrate %D later on. %D %D \showsetup{startlocalfootnotes} %D \showsetup{placelocalfootnotes} % todo: compatibility mode: when first arg is assignment or missing, then all \newtoks\everyplacelocalnotes \appendtoks \enforced\lettonothing\flushnotes \enforced\lettonothing\postponenotes \to \everyplacelocalnotes \newconditional\inlocalnotes \mutable\lettonothing\localnoteslist \permanent\tolerant\protected\def\startlocalnotes[#list]% grouping ? (we used to have a second argument ... settings) {\settrue\inlocalnotes \def\localnoteslist{#list}% \processcommacommand[\localnoteslist]\strc_notes_local_start_step} \permanent\protected\def\stoplocalnotes {\processcommacommand[\localnoteslist]\strc_notes_local_stop_step \setfalse\inlocalnotes} \lettonothing\p_strc_notes_continue \def\strc_notes_local_start_step#tag% {\p_strc_notes_continue{\noteparameter\c!continue}% \ifx\p_strc_notes_continue\v!yes \else \strc_counters_save{#tag}% \strc_counters_reset{#tag}% \fi \clf_savenote{#tag}{store}} \def\strc_notes_local_stop_step#tag% {\p_strc_notes_continue{\noteparameter\c!continue}% \ifx\p_strc_notes_continue\v!yes \else \strc_counters_restore{#tag}% \fi \clf_restorenote{#tag}} \permanent\tolerant\protected\def\placelocalnotes[#tag]#spacer[#settings]% {\doif{\clf_getnotestate{#tag}}{store}{\strc_notes_local_place_indeed{#settings}{#tag}}} \def\strc_notes_local_place_indeed#settings#tag% {\begingroup \edef\currentnote{#tag}% is already set? \the\everyplacelocalnotes % beware, we cannot trust setting \currentnote here \setupcurrentnote[#settings]% later we set height etc for framed \strc_notes_place_local_alternative \strc_notes_set_properties % restore globals (if needed) \endgroup }% TODO: just restore properties \the\everychecknote} % we need to restore the old state %D These commands can be used like: %D %D \startbuffer %D \startlocalnotes[footnote] %D \placetable %D {Some Table} %D \placeontopofeachother %D {\starttable[|l|r|] %D \HL %D \VL Nota\footnote{Bene} \VL Bene\footnote{Nota} \VL\SR %D \VL Bene\footnote{Nota} \VL Nota\footnote{Bene} \VL\SR %D \HL %D \stoptable} %D {\setupnotation[footnote][alternative={serried},distance=.5em,after=\hskip1em]% %D \placelocalnotes[footnote]} %D \stoplocalnotes %D \stopbuffer %D %D \typebuffer %D %D Because this table placement macro expect box content, and thanks to the grouping %D of the local footnotes, we don't need additional braces. %D %D \getbuffer %D \macros %D {placefootnotes} %D %D We still have no decent command for placing footnotes somewhere else than at the %D bottom of the page (for which no user action is needed). Footnotes (endnotes) can %D be placed by using %D %D \showsetup{placefootnotes} \permanent\protected\def\placebottomnotes {\strc_notes_process\strc_notes_place_inserts} \permanent\tolerant\protected\def\placenotes[#list]#spacer[#settings]% {\processcommalist[#list]{\strc_notes_place_indeed{#settings}}} \def\strc_notes_place_indeed#settings#tag% settings note {\edef\currentnote{#tag}% grouping ? \doifelse{\clf_getnotestate{#tag}}{store} \strc_notes_local_place_indeed \strc_notes_global_place_indeed {#settings}{#tag}} \def\strc_notes_global_place_indeed#settings#tag% {\begingroup \setupnote[#tag][#settings]% \strc_notes_place_inserts \endgroup \the\everysetupnote} % to be checked .. synchronize %D Placement \installcorenamespace{notealternative} \permanent\protected\def\installnotealternative#alternative#command% {\defcsname\??notealternative#alternative\endcsname{#command}} \permanent\protected\def\doifnotescollected#tag% {\clf_doifnotecontent{#tag}} \def\strc_notes_place_local_alternative % will be a setup (wrapper) {\doifnotescollected\currentnote {\endgraf \ifvmode \whitespace \noteparameter\c!before \fi \begingroup \strc_notes_set_bodyfont \begincsname\??notealternative\noteparameter\c!alternative\endcsname \endgroup \ifvmode \noteparameter\c!after \fi}} %D A stupid alternative is also provided: %D %D \starttyping %D \setupfootnotes[location=text,alternative=none] %D \stoptyping % setups ? \permanent\def\flushlocalnotes#tag{\clf_flushnotes{#tag}{store}{\noteparameter\c!criterium}} \installnotealternative \v!none {\flushlocalnotes\currentnote} \installnotealternative \empty {\flushlocalnotes\currentnote} \installnotealternative \v!grid % test if n > 0 {\begingroup \setupcurrentnote[\c!location=]% \snaptogrid\hbox {\inheritednoteframed {\flushlocalnotes\currentnote}}% \endgroup} \installnotealternative \v!fixed % test if n > 0 {\begingroup \setupcurrentnote[\c!location=]% \inheritednoteframed {\flushlocalnotes\currentnote}% \endgroup} \installnotealternative \v!columns % redundant {\begingroup \setupcurrentnote[\c!location=]% \inheritednoteframed {\doifelsedimension{\noteparameter\c!width}\donothing{\setexpandednoteparameter\c!width{\the\hsize}}% \startsimplecolumns[\c!distance=\noteparameter\c!columndistance,\c!n=\noteparameter\c!n,\c!width=\noteparameter\c!width]% \flushlocalnotes\currentnote \stopsimplecolumns}% \endgroup} % 0:page 1:firstcolumn 2:lastcolumn \newconstant\c_strc_notes_page_location \protected\def\strc_notes_check_locations {\edef\p_strc_notes_location{\rootnoteparameter\c!location}% \c_strc_notes_page_location \ifx\p_strc_notes_location\v!firstcolumn\plusone \else \ifx\p_strc_notes_location\v!lastcolumn \plustwo \else \zerocount\fi\fi} \appendtoks \strc_notes_check_locations \to \everysynchronizenote % still semi public (but will change) \newif\ifnotespresent \permanent\protected\def\checknotepresence {\notespresentfalse \strc_notes_process\strc_notes_check_presence} \def\strc_notes_check_presence % {\ifdim\page_inserts_get_height\currentnoteinsertionnumber>\zeropoint % not reliable {\ifcase\page_inserts_get_height\currentnoteinsertionnumber\else \notespresenttrue \fi} %D \macros %D {fakenotes} % used in page-mul % \ifdefined\currentnofcolumns\else \def\currentnofcolumns{\nofcolumns} \fi \permanent\protected\def\fakenotes {\ifhmode\endgraf\fi\ifvmode \calculatetotalclevernoteheight \ifdim\totalnoteheight>\zeropoint \kern\totalnoteheight \fi \fi} \permanent\protected\def\fakepagenotes {\ifhmode\endgraf\fi\ifvmode \calculatetotalpagenoteheight \ifdim\totalnoteheight>\zeropoint \kern\totalnoteheight \fi \fi} % used in page-not but not yet ok \newdimen\totalnoteheight \permanent\protected\def\additionaltotalnoteheight#insert% temp hacks anyway {\dimexpr \ifnum\page_inserts_get_height#insert=\zeropoint \zeropoint \orelse\ifnum\page_inserts_get_multiplier#insert=\zeropoint \zeropoint \else % todo: divide by count \page_inserts_get_height #insert +\page_inserts_get_distance#insert% hm, no stretch but a dimen anyway \fi \relax} \permanent\def\docalculatetotalnoteheight {\ifcase\c_strc_notes_page_location % tricky here ! ! ! to be sorted out ! ! ! \advance\totalnoteheight\normalexpanded{\additionaltotalnoteheight\currentnoteinsertionnumber}% \fi} \permanent\def\docalculatetotalclevernoteheight {\ifcase\c_strc_notes_page_location \else % tricky here ! ! ! to be sorted out ! ! ! \advance\totalnoteheight\normalexpanded{\additionaltotalnoteheight\currentnoteinsertionnumber}% \fi} \permanent\def\docalculatetotalpagenoteheight {\advance\totalnoteheight\normalexpanded{\additionaltotalnoteheight\currentnoteinsertionnumber}} \permanent\def\calculatetotalnoteheight {\totalnoteheight\zeropoint\strc_notes_process\docalculatetotalnoteheight} \permanent\def\calculatetotalclevernoteheight{\totalnoteheight\zeropoint\strc_notes_process\docalculatetotalclevernoteheight} \permanent\def\calculatetotalpagenoteheight {\totalnoteheight\zeropoint\strc_notes_process\docalculatetotalpagenoteheight} %D Now how can this mechanism be hooked into \CONTEXT\ without explictly postponing %D footnotes? The solution turned out to be rather simple: %D %D \starttyping %D \everypar {...\flushnotes...} %D \neverypar {...\postponenotes} %D \stoptyping %D %D We can use \type {\neverypar} because in most commands sensitive to footnote %D gobbling we disable \type {\everypar} in favor for \type {\neverypar}. In fact, %D this footnote implementation is the first to use this scheme. %D This is a nasty and new secondary footnote flusher. It can be hooked into \type %D {\everypar} like: %D %D \starttyping %D \appendtoks \synchronizenotes \to \everypar %D \stoptyping % \let\synchronizenotes\relax %D When typesetting footnotes, we have to return to the footnote specific bodyfont %D size, which is in most cases derived from the global document bodyfont size. In %D the previous macros we already used a footnote specific font setting macro. \def\strc_notes_set_bodyfont {\let\strc_notes_set_bodyfont\relax \restoreglobalbodyfont \usebodyfontparameter\noteparameter \usealignparameter\noteparameter} %D The footnote mechanism defaults to a traditional one column way of showing them. %D By default we precede them by a small line. % end notes in the margin: % % \setuptexttexts % [margin] % [] [{\directsetup{notabene}}] % % \startsetups notabene % \vbox to \textheight \bgroup % \setupalign[tolerant] % \topskipcorrection % \placenotes[endnote][before=,after=] % \vfilll % \egroup % \stopsetups \definenote [\v!footnote] \definenote [\v!endnote ] [\c!location=\v!none] % else no break %D Compatibility macros: \permanent\protected\def\setupfootnotedefinition{\setupnotation [\v!footnote]} \permanent\protected\def\setupfootnotes {\setupnote [\v!footnote]} \permanent \def\footnotetext {\setnotetext [\v!footnote]} \permanent\protected\def\placefootnotes {\strc_notes_place_footnotes [\v!footnote]} \permanent\protected\def\placelocalfootnotes {\strc_notes_place_local_footnotes[\v!footnote]} \permanent\protected\def\startlocalfootnotes {\startlocalnotes [\v!footnote]} % alleen footnote \permanent\protected\def\stoplocalfootnotes {\stoplocalnotes } \tolerant\def\strc_notes_place_footnotes[#list]#spacer[#settings]% {\ifarguments\or \placenotes[#list][\c!height=\textheight]% \or \placenotes[#list][#settings,\c!height=\textheight]% \fi} \tolerant\def\strc_notes_place_local_footnotes[#list]#spacer[#settings]% {\ifarguments\or \placelocalnotes[#list][\c!height=\textheight]% \or \placelocalnotes[#list][#settings,\c!height=\textheight]% \fi} %D Goodies: %D %D \starttyping %D \dorecurse {100} { %D test \footnote{\doifnoteonsamepageelse[footnote]{ibidem}{aaa}} %D } %D \stoptyping \permanent\def\doifelsenoteonsamepage#tag{\clf_doifnoteonsamepageasprevious{#tag}} \aliased\let\doifnoteonsamepageelse\doifelsenoteonsamepage %D New trickery: %D \macros %D {note} %D %D Refering to a note is accomplished by the rather short command: %D %D \showsetup{note} %D %D This command is implemented rather straightforward as: \installcorenamespace{notesymbol} \mutable\lettonothing\lastnotesymbol % todo: per class \permanent\tolerant\protected\def\notesymbol[#tag]#keepspacer[#reference]% {\ifnotesenabled \dontleavehmode \begingroup \edef\currentnote{#tag}% \usenotestyleandcolor\c!textstyle\c!textcolor \iftok{#reference}\emptytoks \noteparameter\c!textcommand\lastnotesymbol % check if command double \else \unskip \noteparameter\c!textcommand{\in[#reference]}% command here? \fi \endgroup \fi} \permanent\tolerant\protected\def\note[#tag]#keepspacer[#reference]% {\iftok{#reference}\emptytoks \notesymbol[\v!footnote][#tag]% \else \notesymbol[#tag][#reference]% \fi} % will be redone if needed % % \def\ownnotesymbol#1% #1 gets number passed % {\executeifdefined{\??notesymbol\currentnote}\empty} % % \protected\def\setnotesymbol[#1]#2#3% % {\prewordbreak % prevent lookback % \setgvalue{\??notesymbol#1}{#3} % \strc_notes_inject_symbol} % % \protected\def\ownnote[#1]#2#3#4% % {\setnotesymbol[#1]{#2}{#3}% % \setnotetext [#1]{#4}} % % \defineconversion % [ownnote] % [\ownnotesymbol] % tricky: % % \enabletrackers[nodes.areas] % \enabletrackers[nodes.references] % \enabletrackers[nodes.destinations] % % \setupnotes[interaction=all,rule=no] % \setupinteraction[state=start,focus=standard] % % \starttext % \goto{\input tufte\relax}[page(2)] \par % \ruledhbox{\gotobox{\vtop{\input tufte\relax}}[page(2)]} \par % \ruledhbox{\gotobox{\vbox{\input tufte\relax}}[page(2)]} \par % % \completecontent % % \chapter{Chapter} % % \dorecurse{5}{\input knuth} % a\footnote{\input tufte\par\input ward\relax} % \stoptext %D Bonus: \appendtoks \setsystemmode\currentnote \to \everysynchronizenote \protect \endinput