Inside ConTeXt

From Wiki
Revision as of 13:20, 27 September 2010 by Esteis (talk | contribs) (→‎Passing verbatim text as macro parameter: Added pointer to Programming in LuaTeX's section on verbatim text.)
Jump to navigation Jump to search

< Main Page >

Programming Topics

ConTeXt Features

  • Modes: Conditional processing of text

Commands and Arguments

Module Parameters

Programming Techniques

Debugging

  • Console Mode: Using ConTeXt on keyboard input directly, rather than loading a .tex file.

Using variables

There are several ways to handle variables in ConTeXt. The recommended and easiest method is to use the \setvariables and \getvariable macros. Doing it this way you also avoid to get in conflict with already defined stuff (as variables use their own namespace).

To store variables, you can use the \setvariables macro.

% stores value in variable namespace:key
\setvariables[namespace][key=value]
% stores the expanded value
\setevariables[namespace][key=value]
% global
\setgvariables[namespace][key=value]
% global and expanded value
\setxvariables[namespace][key=value]

Use \getvariable to process a variable. Reading an undefined variable results in the \empty token. This is not a serious problem, as long as you expect text only. But be warned: the compilation process breaks, if you expect a dimension or number. So better take care, that you define your variables, before you use them.

% gets value of the variable namespace:key
\getvariable{namespace}{key}


To avoid problems, also pay attention to the following:

You can set several variables (same namespace) at the same time. So the command \setvariables logically uses the plural form and works with square brackets. On the other hand you can only process one variable at the same time, so \getvariable uses the singular form and works with braces.


OK, here comes a simple example. Let's say, that we want to have variable space before and after a letter macro called \Opening.

\long\def\Opening#1{%
  \getvariable{Letter:opening}{before}
  \noindent{\begstrut#1\endstrut}
  \getvariable{Letter:opening}{after}
}

By using variables in your macros, you can separate the layout definition, so that your macros get much more flexible. Just ensure, that all variables are set, before you use them!

In this example we want to have a blank line in front of the opening, and two blank lines right after it. The value for the second key contains square brackets, so it must be enclosed in braces.

\setvariables[Letter:opening]
  [before=\blank,
   after={\blank[2*big]},
  ]

You can now save this style setup (among others) in a separate file and include it at the start of your document (before \Opening is defined or at least used).

And don't forget: Just ensure, that all variables are set, before you use them!


Using setups for namespaces

Using \setups for a variable namespace allows an easier control over the containing variables. All you have to do is to define the setups namespace:set and/or namespace:reset for a given namespace. Now every time a variable of that namespace is assigned (written), ConTeXt automatically calls these setups. Reading of variables is totally unaffected by these settings. A possible use are default values, calculations and even verification.

So once you have 'setup' your variables proper, you don't have to worry about unset variables and alike any more. Also changes can be made easy, as there is only one common setup. The drawback is the slower speed in use, as every assignment to a variable calls these setups.


To give you the idea, try this example.

The set-part is called

  • right after the definition of the namespace (initialisation) and
  • after a value is assigned to a variable.

The reset-part is called

  • right after any assignment, but still in front of the set-part.
\setupoutput[pdftex]

\startsetups namespace:set
%
\writestatus{VARIABLES}{namespace:set is beeing called..}%
\ {\green [namespace:set]}
  % whatever must be done with your variables after you assign a value
  %
  % (initialisation with defaults,..)
\stopsetups


\startsetups namespace:reset
%
\writestatus{VARIABLES}{namespace:set is beeing called..}%
\ {\green [namespace:reset]}
  % whatever must be done after an assignment (verification, calculation,..)
\stopsetups


% \setups[namespace:set] is automatically called right after 'set' is assigned
\setvariables[namespace]
  [set={\setups[namespace:set]},
   reset={\setups[namespace:reset]},
  ]

% watch for the colors
\setupcolors[state=start]

\starttext
\hairline
{\bf reading has no effect\par}
{\tt Calling \type{\getvariable{namespace}{key}}...\getvariable{namespace}{key}}

\blank
{\bf writing calls reset and set\par}
{\tt Calling \type{\setvariables[namespace][key=value]}...\setvariables[namespace][key=value]}

\stoptext

Defining new commands

Special characters in command names

Some commands have special characters in their names, that TeX normally does not consider to be letters: @, ! and ?. Before and after the use or definition of such protected commands in your input files, the catcode of these characters has to be changed. This is done by \unprotect and \protect:

\unprotect
\def\!test{alfa} 
\protect 

The newly defined command \!test can of course only be called upon when we are in the \unprotected state, otherwise TeX reads the command \!, followed by the word test (and probably complains loudly about not being in math mode). These protection/unprotection commands can be nested. When the nesting becomes deeper than one level, the system reports the current protection level. It is a good habit to always start your macro files with \unprotect and end them with \protect.


Passing verbatim text as macro parameter

(For passing text to LuaTex verbatim, see the Programming in LuaTeX article on this wiki.)

In case you want to write macros that should handle verbatim text, you can use the tex primitives \obeyspaces and \obeylines. \obeyspaces changes the category code of the space character, so that spaces become significant. \obeylines does the same for the newline character.

This works fine for the following example:

\framed{\obeyspaces{A gap from here     to there!}}

But if you pass this text as a parameter for your own macro \TextWithSpaces

\def\TextWithSpaces#1{\framed{\obeyspaces#1}}%
\TextWithSpaces{A gap from here     to there!}

the additional spaces are ignored. This happens because the category code change is not yet in effect when the argument is parsed, and the spaces are removed during parsing. To keep the spaces, the catcode change must be done before the argument is parsed.

Here is a two-part solution for the problem (suggested by Taco Hoekwater):

\def\TextWithSpaces{\bgroup\obeyspaces\doTextWithSpaces}
\def\doTextWithSpaces#1{\framed{#1}\egroup}

Another way is to postpone argument loading (suggested by Hans Hagen).

\def  \TextWithSpaces  {\framed\bgroup\obeyspaces\doTextWithSpaces}
\def\doTextWithSpaces     #1{#1\egroup} 

Both of these produce the desired result:

Setups

In ConTeXt it is easy to create local variables and grouping. Local variables can be simulated as in:

\startsetups whatever
% some useful definitions here
\stopsetups

\definestartstop[whatever][commands=\setups{whatever}]

\startwhatever
Using definitions here.
\stopwhatever

But you can place setups almost everywhere and environment will not be affected by their execution. It is useful to wrap overlay definitions and such in setups as in (copied from Colorful_CD_Inlay page):

\defineoverlay [origin] [\setups{origin}]

\startsetups origin
    \vbox to \overlayheight {
        \vfill\tfxx\setstrut
        \hsize\overlaywidth
        \hfill Fiona Apple\enspace EM\enspace2005\quad\strut\endgraf
        \kern1ex
    }
\stopsetups

You can even do things like:

\starttext
\startsetups settest
\def\command{do something with}
I want to \command{} command.
\stopsetups

\start
\setups{settest}
\stop

\command aaa  % will give "undefined control sequence" error

\stoptext