Difference between revisions of "Inside ConTeXt"

From Wiki
Jump to navigation Jump to search
m (category added (Inside ConTeXt))
(Add hints on bracket usage; c&p from the list: https://www.mail-archive.com/ntg-context@ntg.nl/msg87937.html)
 
(35 intermediate revisions by 15 users not shown)
Line 1: Line 1:
< [[Main Page]]
+
= Programming Topics =
  
== Using variables ==
+
== ConTeXt Features ==
 +
* [[Modes]]: Conditional processing of text
 +
* [[Setups]]: An alternative to macros for storing chunks of code
  
<texcode>
+
== Commands and Arguments ==
\setvariables[namespace][key=value]
+
* [[System Macros]] (''Recommended reading''. Topics: temporary variables, expansion control, argument grabbing and handling, definitions and assignments, branches and decisions, cases, comma separated lists, assignments and parameters, user interaction.)
\getvariable{namespace}{key}
+
* [[Programming in LuaTeX]] (Topic: alleviating the more cumbersome sides of TeX programming.)
</texcode>
+
* [[Commands with KeyVal arguments|Commands with Key=Value arguments]]: (Topic: things like <code>\command[thiskey=thatvalue]</code>.)
 +
* [[Commands with optional arguments]]: (Topic: one or more optional arguments within brackets.)
 +
 
 +
== Module Parameters ==
 +
* [[Module Parameters]]: Passing parameters to modules.
  
== Defining new commands ==
+
== Programming Techniques ==
'''Special characters in command names'''
+
* [[Processing Lists]]: Processing lists of values
 +
* [[Counters]]: Manipulating counters in context
 +
* [[Expressions]]: Evaluating expressions of type number, dimen, glue or muglue
 +
* [[Executesystemcommand]]: process contents of an environment by another program
 +
* Loops and expansion [http://randomdeterminism.wordpress.com/2009/03/05/tex-programming-the-past-the-present-and-the-future/ (blog post)]
  
Some commands have special characters in their names, that TeX normally does not consider to be
+
== Debugging ==
letters: <tt>@</tt>, <tt>!</tt> and <tt>?</tt>.
 
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 <cmd>unprotect</cmd> and <cmd>protect</cmd>:
 
  
<texcode>
+
* [[Console Mode]]: Using ConTeXt on keyboard input directly, rather than loading a <tt>.tex</tt> file.
\unprotect
 
\def\!test{alfa}
 
\protect
 
</texcode>
 
  
The newly defined command <tt>\!test</tt> can of course only be called upon when we are in the <cmd>unprotect</cmd>ed state, otherwise TeX reads the command <tt>\!</tt>, followed by the word <tt>test</tt> (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 <cmd>unprotect</cmd> and end them with <cmd>protect</cmd>.
+
= Use of brackets =
  
'''See also''':
+
One must '''not''' confuse with the LaTeX convention where "mandatory"
[[Commands with KeyVal arguments|Commands with Key=Value arguments]],
+
arguments are contained in curly braces and brackets indicate
[[Commands with optional arguments]]
+
"optional" arguments.
>
 
  
== Processing lists of values ==
+
Curly braces not only give grouping but generally
=== Processing a comma-separated list of values ===
+
are used for objects to be typeset, as for \in{Figure}{a} [fig:ref].
  
Suppose you defined a command like this one somewhere in your document:
+
For new users, it is worth repeating here that arguments within braces
<texcode>
+
can be either a comma-separated list of words OR a comma-separated
\def\IHaveTo#1#2{I have to #1 on #2.\par}
+
list of keyword=value pairs, BUT NOT A MIXTURE OF BOTH. Generally, a
</texcode>
+
keyword=value exists for all words, for example \cite[authoryear][ref]
So calling
+
and \cite[alternative=authoryear,reference=ref]
<texcode>
 
\IHaveTo{tidy up}{Monday}
 
</texcode>
 
This will print out:
 
  
<context>
+
values can be grouped using curly braces, as in
\def\IHaveTo#1#2{I have to #1 on #2.\par}
+
\cite[alternative=authoryear,lefttext={{see },}][ref1,ref2] where the
\IHaveTo{tidy up}{Monday}
+
lefttext is associated with the first cite reference (and none with the
</context>
+
second). This can be tricky but is in fact rather straight-forward.
  
But sometimes you have to repeat some task more than once. In this case you can define a new command:
+
= Using variables =
<texcode>
 
\def\MyMumOrderedMeTo[#1]#2%
 
  {\processcommalist[#1]{\IHaveTo{#2}}}
 
</texcode>
 
Calling
 
<texcode>
 
\MyMumOrderedMeTo[Monday,Wednesday,Saturday]{tidy up}
 
</texcode>
 
will spare you some typing <i>(but not some tidying up!)</i>:
 
  
<context>
+
There are several ways to handle variables in ConTeXt.
\def\IHaveTo#1#2{I have to #1 on #2.\par}
+
The recommended and easiest method is to use the
\def\MyMumOrderedMeTo[#1]#2%
+
<tt>\setvariables</tt> and <tt>\getvariable</tt> macros.
  {\processcommalist[#1]{\IHaveTo{#2}}}
+
Doing it this way you also avoid to get in conflict with
\MyMumOrderedMeTo[Monday,Wednesday,Saturday]{tidy up}
+
already defined stuff (as variables use their own namespace).
</context>
 
  
 +
To store variables, you can use the <tt>\setvariables</tt>
 +
macro.
  
In case a command <tt>\IHaveTo</tt> is already defined in a slightly different way:
 
 
<texcode>
 
<texcode>
\def\IHaveTo[#1]#2{I have to #2 on #1.\par}
+
% 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]
 
</texcode>
 
</texcode>
you can define <tt>\MyMumOrderedMeTo</tt> as:
+
 
 +
Use <tt>\getvariable</tt> to process a variable. Reading an undefined
 +
variable results in the <tt>\empty</tt> 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.
 +
 
 
<texcode>
 
<texcode>
\def\MyMumOrderedMeTo[#1]#2%
+
% gets value of the variable namespace:key
  {\begingroup
+
\getvariable{namespace}{key}
  \def\processitem##1{\IHaveTo[##1]{#2}}%
 
  \processcommalist[#1]\processitem
 
  \endgroup}
 
 
</texcode>
 
</texcode>
  
This, again, produces:
+
To avoid problems, also pay attention to the following:
  
<context>
+
You can set several variables (same namespace) at the same time.
\def\IHaveTo[#1]#2{I have to #2 on #1.\par}
+
So the command <tt>\setvariables</tt> logically uses the '''plural''' form
\def\MyMumOrderedMeTo[#1]#2%
+
and works with '''square brackets'''.
  {\begingroup
+
On the other hand you can only process one variable at the same time, so
  \def\processitem##1{\IHaveTo[##1]{#2}}%
+
<tt>\getvariable</tt> uses the '''singular''' form and works with '''braces'''.
  \processcommalist[#1]\processitem
 
  \endgroup}
 
\MyMumOrderedMeTo[Monday,Wednesday,Saturday]{tidy up}
 
</context>
 
  
=== Processing a dash-separated list of values ===
+
OK, here comes a simple example. Let's say, that we want to have variable
 +
space before and after a letter macro called <tt>\Opening</tt>.
  
Sometimes you have more work to do than just that boring stuff at home. And as it is quite important as well, you don't want to loose your time enumerating all of the tasks. Being able to do something like
 
 
<texcode>
 
<texcode>
\IHaveToDoTheTasks[1-4,7,9-11]{until tomorrow}
+
\long\def\Opening#1{%
 +
  \getvariable{Letter:opening}{before}
 +
  \noindent{\begstrut#1\endstrut}
 +
  \getvariable{Letter:opening}{after}
 +
}
 
</texcode>
 
</texcode>
may sound like a good idea.
 
  
Suppose you already defined:
+
By using variables in your macros, you can separate the layout definition,
<texcode>
+
so that your macros get much more flexible.
\def\IHaveToDoTheTask[#1]#2{The task #1 has to be done #2.\par}
+
Just ensure, that all variables are set, before you use them!
</texcode>
 
  
You have to define some macros first (thanks to Taco!):
+
In this example we want to have a blank line in front of the opening, and
<texcode>
+
two blank lines right after it. The value for the second key contains
% a few auxiliary core macros are needed to uncompress the list.
+
square brackets, so it must be enclosed in braces.
%
 
% \uncompresslist is the twin of the already existing \compresslist
 
% which works in the other direction (syst-new)
 
%
 
\unprotect
 
 
 
% I guess this function is already available but couldnt find it...
 
%
 
\def\apptomac#1#2%
 
  {\ifx#1\empty\def#1{#2}\else \@EA\def\@EA#1\@EA{#1,#2}\fi}
 
 
 
% the next macro does this:
 
%
 
% \itemwithdash<<9-11>>- => \dorecurse {<<1+11-9>>}
 
%    {\apptomac\uncompressedlist<<9-1+\recurselevel>>}
 
%
 
% (the 1+ and -1 are needed to solve a counter offset.)
 
\def\itemwithdash#1-#2-%
 
  {\@EA\dorecurse\@EA
 
    {\the\numexpr 1+#2-#1\relax}%
 
    {\@EA\apptomac\@EA\uncompressedlist\@EA
 
      {\the\numexpr #1-1+\recurselevel\relax}}}%
 
 
 
% top level. The result will be in \uncompressedlist
 
\def\uncompresslist[#1]%
 
  {\def\uncompressedlist{}%
 
  \def\processitem##1%
 
    {\doifinstringelse{-}{##1}
 
      {\itemwithdash##1-}
 
      {\apptomac\uncompressedlist{##1}}}%
 
  \processcommalist[#1]\processitem }
 
 
 
\protect
 
</texcode>
 
  
And then you're ready to define
 
 
<texcode>
 
<texcode>
\def\IHaveToDoTheTasks[#1]#2%
+
\setvariables[Letter:opening]
   {\begingroup
+
   [before=\blank,
   \uncompresslist[#1]% <= Yeah!
+
   after={\blank[2*big]},
  \def\processitem##1{\IHaveToDoTheTask[##1]{#2}}%
+
  ]
  \processcommacommand[\uncompressedlist]\processitem
 
  \endgroup}
 
 
</texcode>
 
</texcode>
  
Guess what! Your <tt>\IHaveToDoTheTasks[1-4,7,9-11]{until tomorrow}</tt> results in:
+
You can now save this style setup (among others) in a separate file and
 +
include it at the start of your document (before <tt>\Opening</tt> is
 +
defined or at least used).
  
<context>
+
And don't forget:
\def\IHaveToDoTheTask[#1]#2{The task #1 has to be done #2.\par}
+
'''Ensure that all variables are set before you use them!'''
  
% a few auxiliary core macros are needed to uncompress the list.
+
== CLD ==
%
+
How to pass variable from TeX to Lua and vice versa? See [[CLD_passing_variables#Variables|CLD passing variables]].
% \uncompresslist is the twin of the already existing \compresslist
 
% which works in the other direction (syst-new)
 
%
 
\unprotect
 
  
% I guess this function is already available but couldnt find it...
+
= Defining new commands =
%
 
\def\apptomac#1#2%
 
  {\ifx#1\empty\def#1{#2}\else \@EA\def\@EA#1\@EA{#1,#2}\fi}
 
  
% the next macro does this:
+
== Special characters in command names ==
%
 
% \itemwithdash<<9-11>>- => \dorecurse {<<1+11-9>>}
 
%    {\apptomac\uncompressedlist<<9-1+\recurselevel>>}
 
%
 
% (the 1+ and -1 are needed to solve a counter offset.)
 
\def\itemwithdash#1-#2-%
 
  {\@EA\dorecurse\@EA
 
    {\the\numexpr 1+#2-#1\relax}%
 
    {\@EA\apptomac\@EA\uncompressedlist\@EA
 
      {\the\numexpr #1-1+\recurselevel\relax}}}%
 
  
% top level. The result will be in \uncompressedlist
+
Some commands have special characters in their names, that TeX normally does not consider to be  
\def\uncompresslist[#1]%
+
letters: <tt>@</tt>, <tt>!</tt> and <tt>?</tt>.
  {\def\uncompressedlist{}%
+
Before and after the use or definition of such protected commands in your input files, the catcode of these
  \def\processitem##1%
+
characters has to be changed. This is done by {{cmd|unprotect}} and {{cmd|protect}}:
    {\doifinstringelse{-}{##1}
 
      {\itemwithdash##1-}
 
      {\apptomac\uncompressedlist{##1}}}%
 
  \processcommalist[#1]\processitem }
 
  
\protect
+
<texcode>
 
+
\unprotect
\def\IHaveToDoTheTasks[#1]#2%
+
\def\!test{alfa}  
  {\begingroup
+
\protect
  \uncompresslist[#1]% <= Yeah!
+
</texcode>
  \def\processitem##1{\IHaveToDoTheTask[##1]{#2}}%
 
  \processcommacommand[\uncompressedlist]\processitem
 
  \endgroup}
 
 
 
\IHaveToDoTheTasks[1-4,7,9-11]{until tomorrow}
 
</context>
 
  
So - what are you still waiting for? Go back to work and do them right away!
+
The newly defined command <tt>\!test</tt> can of course only be called upon when we are in the {{cmd|unprotect}}ed state, otherwise TeX reads the command <tt>\!</tt>, followed by the word <tt>test</tt> (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 {{cmd|unprotect}} and end them with {{cmd|protect}}.
  
=== Comments ===
 
Resulted from thread [http://archive.contextgarden.net/thread/20050704.151237.f815d89d.html] and will be used in some modules such as [[RawSteps]]. It would be nice if processing dash-separated lists of values would make it into the ConTeXt core.
 
  
 +
= Passing verbatim text as macro parameter =
  
== Passing verbatim text as macro parameter ==
+
(For passing text to LuaTex verbatim, see the [[Programming_in_LuaTeX#Manipulating_verbatim_text_for_dummies|Programming in LuaTeX]] article on this wiki.)
  
 
In case you want to write macros that should handle verbatim text,
 
In case you want to write macros that should handle verbatim text,
Line 267: Line 201:
 
</context>
 
</context>
  
[[Category:Inside ConTeXt]]
+
[[Category:Programming and Databases]]
 +
[[Category:Tools]]

Latest revision as of 10:11, 16 December 2021

Programming Topics

ConTeXt Features

  • Modes: Conditional processing of text
  • Setups: An alternative to macros for storing chunks of code

Commands and Arguments

  • System Macros (Recommended reading. Topics: temporary variables, expansion control, argument grabbing and handling, definitions and assignments, branches and decisions, cases, comma separated lists, assignments and parameters, user interaction.)
  • Programming in LuaTeX (Topic: alleviating the more cumbersome sides of TeX programming.)
  • Commands with Key=Value arguments: (Topic: things like \command[thiskey=thatvalue].)
  • Commands with optional arguments: (Topic: one or more optional arguments within brackets.)

Module Parameters

Programming Techniques

Debugging

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

Use of brackets

One must not confuse with the LaTeX convention where "mandatory" arguments are contained in curly braces and brackets indicate "optional" arguments.

Curly braces not only give grouping but generally are used for objects to be typeset, as for \in{Figure}{a} [fig:ref].

For new users, it is worth repeating here that arguments within braces can be either a comma-separated list of words OR a comma-separated list of keyword=value pairs, BUT NOT A MIXTURE OF BOTH. Generally, a keyword=value exists for all words, for example \cite[authoryear][ref] and \cite[alternative=authoryear,reference=ref]

values can be grouped using curly braces, as in \cite[alternative=authoryear,lefttext={{see },}][ref1,ref2] where the lefttext is associated with the first cite reference (and none with the second). This can be tricky but is in fact rather straight-forward.

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: Ensure that all variables are set before you use them!

CLD

How to pass variable from TeX to Lua and vice versa? See CLD passing variables.

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: