Difference between revisions of "Inside ConTeXt"

From Wiki
Jump to navigation Jump to search
(Edited text for clarity (and extraneous commas), added examples.)
(Added real examples to processing comma-separated lists.)
Line 40: Line 40:
 
\IHaveTo{tidy up}{Monday}
 
\IHaveTo{tidy up}{Monday}
 
</texcode>
 
</texcode>
Will print out
+
This will print out:
I have to tidy up on Monday.
+
 
 +
<context>
 +
\def\IHaveTo#1#2{I have to #1 on #2.\par}
 +
\IHaveTo{tidy up}{Monday}
 +
</context>
  
 
But sometimes you have to repeat some task more than once. In this case you can define a new command:
 
But sometimes you have to repeat some task more than once. In this case you can define a new command:
Line 52: Line 56:
 
\MyMumOrderedMeTo[Monday,Wednesday,Saturday]{tidy up}
 
\MyMumOrderedMeTo[Monday,Wednesday,Saturday]{tidy up}
 
</texcode>
 
</texcode>
will spare you some typing <i>(however not tidying up!)</i>:
+
will spare you some typing <i>(but not some tidying up!)</i>:
 +
 
 +
<context>
 +
\def\IHaveTo#1#2{I have to #1 on #2.\par}
 +
\def\MyMumOrderedMeTo[#1]#2%
 +
  {\processcommalist[#1]{\IHaveTo{#2}}}
 +
\MyMumOrderedMeTo[Monday,Wednesday,Saturday]{tidy up}
 +
</context>
  
I have to tidy up on Monday.
 
I have to tidy up on Wednesday.
 
I have to tidy up on Saturday.
 
  
 
In case a command <tt>\IHaveTo</tt> is already defined in a slightly different way:
 
In case a command <tt>\IHaveTo</tt> is already defined in a slightly different way:
Line 70: Line 78:
 
   \endgroup}
 
   \endgroup}
 
</texcode>
 
</texcode>
 +
 +
This, again, produces:
 +
 +
<context>
 +
\def\IHaveTo[#1]#2{I have to #2 on #1.\par}
 +
\def\MyMumOrderedMeTo[#1]#2%
 +
  {\begingroup
 +
  \def\processitem##1{\IHaveTo[##1]{#2}}%
 +
  \processcommalist[#1]\processitem
 +
  \endgroup}
 +
\MyMumOrderedMeTo[Monday,Wednesday,Saturday]{tidy up}
 +
</context>
  
 
=== Processing a dash-separated list of values ===
 
=== Processing a dash-separated list of values ===

Revision as of 01:07, 4 August 2005

< Main Page

Using variables

\setvariables[namespace][key=value]
\getvariable{namespace}{key}

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.

See also: Commands with Key=Value arguments, Commands with optional arguments >

Processing lists of values

Processing a comma-separated list of values

Suppose you defined a command like this one somewhere in your document:

\def\IHaveTo#1#2{I have to #1 on #2.\par}

So calling

\IHaveTo{tidy up}{Monday}

This will print out:

But sometimes you have to repeat some task more than once. In this case you can define a new command:

\def\MyMumOrderedMeTo[#1]#2%
  {\processcommalist[#1]{\IHaveTo{#2}}}

Calling

\MyMumOrderedMeTo[Monday,Wednesday,Saturday]{tidy up}

will spare you some typing (but not some tidying up!):


In case a command \IHaveTo is already defined in a slightly different way:

\def\IHaveTo[#1]#2{I have to #2 on #1.\par}

you can define \MyMumOrderedMeTo as:

\def\MyMumOrderedMeTo[#1]#2%
  {\begingroup
   \def\processitem##1{\IHaveTo[##1]{#2}}%
   \processcommalist[#1]\processitem
   \endgroup}

This, again, produces:

Processing a dash-separated list of values

Sometimes you have more work to do than just that borring 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

\IHaveToDoTheTasks[1-4,7,9-11]{until tomorrow}

may sound like a good idea.

Suppose you already defined:

\def\IHaveToDoTheTask[#1]#2{The task #1 has to be done #2.\par}

You have to define some macros first (thanks to Taco!):

% a few auxiliary core macros are needed to uncompress the list.
%
% \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

And then you're ready to define

\def\IHaveToDoTheTasks[#1]#2%
  {\begingroup
   \uncompresslist[#1]% <= Yeah!
   \def\processitem##1{\IHaveToDoTheTask[##1]{#2}}%
   \processcommacommand[\uncompressedlist]\processitem
   \endgroup}

Guess what! Your \IHaveToDoTheTasks[1-4,7,9-11]{until tomorrow} resulted in:

The task 1 has to be done until tomorrow.
The task 2 has to be done until tomorrow.
The task 3 has to be done until tomorrow.
The task 4 has to be done until tomorrow.
The task 7 has to be done until tomorrow.
The task 9 has to be done until tomorrow.
The task 10 has to be done until tomorrow.
The task 11 has to be done until tomorrow.

So - what are you still waiting for? Go back to work and do them right away!

Comments

Resulted from thread [1] 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

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: