3

This is another approach to solve the problem in question "How can I write to file part of text between two flags?".

I try to "remember" parts of text to use them later. So, I do

\newbox\@tmpbox
\def\startsync{\setbox\@tmpbox\vbox\bgroup}
\def\esync{\egroup\writepart}
\def\syncpoint{\esync\startsync}
\newcount\p@rts
\p@rts0
\long\def\writepart{
    \advance\p@rts1
    \@roman\p@rts\par
    \expandafter\xdef\csname apart\@roman\p@rts\endcsname{\unvbox\@tmpbox}
}
\def\insrt#1{\csname apart\@roman #1\endcsname}

but TeX don't do what I want: \xdef defines macro like \aparti with unexpanded \unvbox\@tmpbox, so, when I call \insrt{1}, I see contents of latest text portion instead of first!

How can I define this macro so, that every \apartXXX would be expanded into corresponding text portion?

  • 3
    the contents of a box are not tokens, you can not store them in a macro. – David Carlisle Feb 16 '16 at 15:07
  • Perhaps you could just save the text in a regular macro. \def\partI{Text} – musarithmia Feb 16 '16 at 18:32
  • @AndrewCashner, I want to simplify, not to write something like \addblock{a lot of paragraphs}. I will try also some variants. – Eddy_Em Feb 16 '16 at 19:32
  • But you intend to write \startsync A lot of paragraphs...\esync, don’t you? As D.C. says, you need to capture your content as tokens, not as a (digested) vertical list! You might want to consider the environ package, that lets you capture the contents of an environment in a macro called \BODY, that you can subsequently copy to another control sequence (keep in mind, however, that this is only syntactic sugar for something that remains essentially equivalent to \def\BODY{...}). – GuM Feb 16 '16 at 20:16
3

I think you want something like this; note that you can't store boxes in macros, but you can store tokens.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn

\seq_new:N \l_eddyem_sync_items_seq
\int_new:N \g_eddyem_sync_part_int

\cs_new_protected:Npn \startsync #1 \endsync
 {
  \seq_set_split:Nnn \l_eddyem_sync_items_seq { \syncpoint } { #1 }
  \seq_map_inline:Nn \l_eddyem_sync_items_seq
   {
    \int_gincr:N \g_eddyem_sync_part_int
    \tl_new:c { g_eddyem_sync_part \int_to_roman:n { \g_eddyem_sync_part_int} _tl }
    \tl_gset:cn { g_eddyem_sync_part \int_to_roman:n { \g_eddyem_sync_part_int} _tl } { ##1 }
    \int_to_roman:n \g_eddyem_sync_part_int\par
   }
 }

\NewDocumentCommand{\insrt}{m}
 {
  \tl_use:c { g_eddyem_sync_part \int_to_roman:n { #1 } _tl }
 }
\ExplSyntaxOff

\begin{document}

\startsync
This is the first part
\syncpoint
This is the second part
\syncpoint
This is the third part
\endsync

Some text in between

\startsync
This is the fourth part
\endsync

Some text before printing the parts

\insrt{1}

\insrt{2}

\insrt{4}

\insrt{3}

\end{document}

enter image description here

How does this work? First we collect all tokens between \startsync and \endsync, then split items at \syncpoint (if it appears, which is optional).

After the splitting, each item is saved in a token list variable, indexed by an integer variable that's incremented at each found item.

The macro \insrt just takes its argument and delivers the contents of the appropriate variable.

  • That's great! Thanks! If I have anything figured ... Are you sure that it cannot be done with simple tex commands, not that strange macros? – Eddy_Em Feb 16 '16 at 20:31
  • @Eddy_Em Of course it can be done; but why doing the hard work when you have predefined functions that do it for you? Would you program a browser in Assembler? – egreg Feb 16 '16 at 20:32
  • I try to use external packages as small as possible. Don't like to read weird documentation to packages. The macros you write absolutely unclear for me. That's like a lots of \expandafter in Knuths book ☺ – Eddy_Em Feb 16 '16 at 20:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.