3

In my document, I have several instances of a tabulate environment, all of which look like this:

\startplacetable[location=force,number=no]
  \starttabulate[|l|r|rw(2cm)|]
    \HL \NC {\bf Process} \NC {\bf\em T} \NC {\bf\em C} \NC \NR \HL
    % --- varying content here, example line: ---
    \NC A \NC 200ms \NC 20ms \NC \NR
    % -------------------------------------------
    \HL
  \stoptabulate
\stopplacetable

So I try to create a custom start-stop environment:

\definestartstop[ProcessTable][
  before={%
    \startplacetable[location=force,number=no]
      \starttabulate[|l|r|rw(2cm)|]
        \HL \NC {\bf Process} \NC {\bf\em T} \NC {\bf\em C} \NC \NR \HL
    },%
  after={%
        \HL
      \stoptabulate
    \stopplacetable
  }%
]

This, when used in a document, never finishes, e.g.:

\starttext
  \startProcessTable
    \NC A \NC 200ms \NC 20ms \NC \NR
  \stopProcessTable
\stoptext

last two lines of ConTeXt output:

close source    > level 2, order 3, name '/.../test.tex'
close source    > level 1, order 3, name '/usr/local/context/tex/texmf-context/tex/context/base/mkiv/cont-yes.mkiv'

When trying to use it together with the original code:

\starttext
  \startProcessTable
    \NC A \NC 200ms \NC 20ms \NC \NR
  \stopProcessTable

  \startplacetable[location=force,number=no]
    \starttabulate[|l|r|rw(2cm)|]
      \HL \NC {\bf Process} \NC {\bf\em T} \NC {\bf\em C} \NC \NR \HL
    \stoptabulate
  \stopplacetable
\stoptext

I get this output which hints to something being seriously wrong:

tex error       > tex error on line 34 in file /.../test.tex: ! Missing } inserted

<inserted text>
}
<to be read again>
\endtemplate
<template> \endtemplate

\tabl_tabulate_column_normal ...\unskip \aligntab
                                                  \ifconditional \c_tabl_tab...
\tabl_tabulate_insert_body ...\dotagconstruct \NC
                                                  A \NC 200ms \NC 20ms \NC \...
\tabl_tabulate_insert_content ...late_insert_body
                                                  \tabl_tabulate_insert_foot...
...
l.34     \stoptabulate


24     %]
25
26     \starttext
27       \startProcessTable
28         \NC A \NC 200ms \NC 20ms \NC \NR
29       \stopProcessTable
30
31       \startplacetable[location=force,number=no]
32         \starttabulate[|l|r|rw(2cm)|]
33           \HL \NC {\bf Process} \NC {\bf\em T} \NC {\bf\em C} \NC \NR \HL
34 >>      \stoptabulate
35       \stopplacetable
36     \stoptext

While trying to solve this, I discovered that there is \definetabulate, so I tried to use that instead:

\definetabulate[ProcessTable][|l|r|rw(2cm)|]
\setuptabulate[ProcessTable][
  before={%
    \startplacetable[location=force,number=no]
  },
  inner={%
    \HL \NC {\bf Process} \NC {\bf\em T} \NC {\bf\em C} \NC \NR \HL
  },
  after={%
    \stopplacetable
  }%
]

This compiles, but does not render the table (i.e. the text from both header and body is rendered, but without lines and alignment). I assume that I am using the inner parameter wrong, but I found no documentation or example on it. When I remove the inner parameter, the table renders, but without the header.

How can I properly setup such an environment?

2 Answers 2

5

Looks like \starttabulate is looking ahead for \stoptabulate, so putting it into \definestartstop will not work. You can work around that by simply collecting the table content as an argument.

\unexpanded\long\def\startProcessTable#1\stopProcessTable
  {\startplacetable[location=force,number=no]
    \starttabulate[|l|r|rw(2cm)|]
      \HL \NC {\bf Process} \NC {\bf\em T} \NC {\bf\em C} \NC \NR \HL
      #1%
      \HL
    \stoptabulate
  \stopplacetable}

\starttext
  \startProcessTable
    \NC A \NC 200ms \NC 20ms \NC \NR
  \stopProcessTable
\stoptext

enter image description here

If you need to reuse the table content later, or process it in any way, I recommend using buffers:

\unprotect

\unexpanded\def\startProcessTable
  {\buff_pickup{ProcessTable}{startProcessTable}{stopProcessTable}{\relax}{\process_table}{\zerocount}}

\unexpanded\def\process_table
  {\startplacetable[location=force,number=no]
    \starttabulate[|l|r|rw(2cm)|]
      \HL \NC {\bf Process} \NC {\bf\em T} \NC {\bf\em C} \NC \NR \HL
      \rawbuffer{ProcessTable}%
      \HL
    \stoptabulate
  \stopplacetable}

\protect

\starttext
  \startProcessTable
    \NC A \NC 200ms \NC 20ms \NC \NR
  \stopProcessTable
\stoptext
1
  • 3
    To store the content of a environment in a buffer you can use the \grabbufferdata command, e.g. \define\startProcessTable{\grabbufferdata[ProcessTable][startProcessTable][stopProcessTable]}. To flush the content of the buffer at the end of the environment you can create a custom stop command, e.g. \define\stopProcessTable{\getbufferdata[ProcessTable]}. Commented Dec 4, 2017 at 23:54
4

In order for a table to have a specific first and last row, you can use \starttablehead and \starttabletail (there is a bug in the tabl-tbl.mkiv; I'll send a bugfix to the context list, but in the meanwhile, I have included the fix below as well).

\starttabulatehead
  \HL \NC {\bf Process} \NC {\bf\em T} \NC {\bf\em C} \NC \NR \HL
\stoptabulatehead

\starttabulatetail
  \HL
\stoptabulatetail

\starttext
\starttabulate[|l|r|rw(2cm)|]
  \NC A \NC 200ms \NC 20ms \NC \NR
  \NC B \NC 400ms \NC 30ms \NC \NR
\stoptabulate
\stoptext

However, this adds a head and tail to every table. To apply these to specific tables, we can simply define a new tabulate:

\definetabulate[process][|l|r|rw(2cm)|]

\starttabulatehead[process]
  \HL \NC {\bf Process} \NC {\bf\em T} \NC {\bf\em C} \NC \NR \HL
\stoptabulatehead

\starttabulatetail[process]
  \HL
\stoptabulatetail

\starttext
\startprocess
  \NC A \NC 200ms \NC 20ms \NC \NR
  \NC B \NC 400ms \NC 30ms \NC \NR
\stopprocess
\stoptext

Now, if you are using a float to center the table, you can add:

\setuptabulate
  [process]
  [
    before={\startplacetable[location={force,none}]\insidefloatfalse},
    after={\stopplacetable},
  ]

The \insidefloatfalse is needed to ensure that after key is applied; otherwise, ConTeXt starts in outer mode, applies the before key, and when it is time to apply the after key, it checks that the table is inside a float and does not apply the after key!

So, here is the complete code (with the bugfix for tabl-tab.mkiv)

\unprotect
\def\tabl_tabulate_check_full_content % - needed, else confusion with \c!header
  {\ifcsname\??tabulatehead\currenttabulation\endcsname
    %\expandafter\ifx\csname\??tabulatehead\currenttabulation\endcsname\empty
     \expandafter\ifx\lastnamedcs\empty
       \let\tabl_tabulate_insert_head\empty
     \else
       \let\tabl_tabulate_insert_head\tabl_tabulate_insert_head_content
     \fi
   \else
     \let\tabl_tabulate_insert_head\empty
   \fi
   \ifcsname\??tabulatefoot\currenttabulation\endcsname
     \expandafter\ifx\csname\??tabulatefoot\currenttabulation\endcsname\empty
    %\expandafter\ifx\lastnamedcs\empty
       \let\tabl_tabulate_insert_foot\empty
     \else
       \let\tabl_tabulate_insert_foot\tabl_tabulate_insert_foot_content
     \fi
   \else
     \let\tabl_tabulate_insert_foot\empty
   \fi}
\protect

\definetabulate[process][|l|r|rw(2cm)|]

\setuptabulate
  [process]
  [
    before={\startplacetable[location={force,none}]\insidefloatfalse},
    after={\stopplacetable},
  ]

\starttabulatehead[process]
  \HL \NC {\bf Process} \NC {\bf\em T} \NC {\bf\em C} \NC \NR \HL
\stoptabulatehead

\starttabulatetail[process]
  \HL
\stoptabulatetail

\starttext

\input knuth

\startprocess
  \NC A \NC 200ms \NC 20ms \NC \NR
  \NC B \NC 400ms \NC 30ms \NC \NR
\stopprocess

\input knuth

\startprocess
  \NC A \NC 200ms \NC 20ms \NC \NR
  \NC B \NC 400ms \NC 30ms \NC \NR
\stopprocess

\input knuth

\stoptext

which gives

enter image description here

You must log in to answer this question.

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