Difference between revisions of "Commands with KeyVal arguments"

From Wiki
Jump to navigation Jump to search
(added texcode and cmd markup)
m (String Manipulation --> String manipulation)
(9 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
< [[Inside ConTeXt]]
 
< [[Inside ConTeXt]]
  
(a post on the mailing list by Taco Hoekwater from 2004-06-28:)
+
== Using Lua ==
 +
 
 +
There is a lovely set of functions in the <tt>utilities.parsers</tt> table that turns strings into nice Lua-accessible tables of various kinds. An example is given below; the functions are documented on the [[String_manipulation#util-prs.lua|string manipulation]] page.
 +
 
 +
<texcode>
 +
\startluacode
 +
userdata = userdata or { }
 +
 
 +
function userdata.mycommand(keywords, keyvals)
 +
    keyword_options = utilities.parsers.settings_to_array(keywords)
 +
    named_values = utilities.parsers.settings_to_hash(keyvals)
 +
   
 +
    -- do stuff based on that array and that hashtable.
 +
end
 +
\stopluacode
 +
 
 +
\def\mycommand[#1][#2]{\ctxlua{
 +
    userdata.mycommand('#1', '#2')}   
 +
 
 +
\mycommand[top, inmargin, now][color=green, roof=gabled]
 +
</texcode>
 +
 
 +
== Using TeX ==
 +
 
 +
This section is based on a post on the mailing list by Taco Hoekwater from [[http://www.mail-archive.com/ntg-context@ntg.nl/msg03235.html 2004-06-28]].
 +
 
 +
=== Example code ===
 +
 
 +
<texcode>
 +
\unprotect % enable exclamations in macro names
 +
 
 +
% Helper function: if the user specifies nothing, throw an error
 +
\def\errorDir{%
 +
  \def\Dir{0}% error recovery
 +
  \message{Please supply "Dir" argument}%
 +
}
 +
 
 +
% Helper function: process Dir=... other than Up/Down/Left/Right
 +
% Accept numbers, else throw an error
 +
\def\checkDir#1{%
 +
  \doifnumberelse {#1}
 +
                  {\def\Dir{#1}}
 +
                  {\message{Invalid "Dir" argument! (#1)}}
 +
}
 +
 
 +
% Defining our command that accepts key=val
 +
\def\MyZigzag#1[#2]{%
 +
  % the #1 makes sure we allow a space before the bracket
 +
 
 +
  % create commands \ZZDir, \ZZLinewidth (default 1pt), etc.
 +
  \getparameters[ZZ][Dir=,Linewidth=1pt,Color=Red,Width=3em,#2]
 +
 
 +
  % define an alias
 +
  \edef\mywidth{\ZZWidth}%
 +
 
 +
  % accept keywords for Dir= (and map those keywords to numbers)
 +
  %\expandafter\processaction\expandafter[\ZZDir] % mkii
 +
  \processaction[\ZZDir]                          % mkiv
 +
[      Down=>\def\Dir{270},
 +
      Left=>\def\Dir{180},
 +
          Up=>\def\Dir{90},
 +
      Right=>\def\Dir{0},
 +
\s!default=>\errorDir,
 +
\s!unknown=>\checkDir{\ZZDir}]
 +
} % this brace belongs to \def!
 +
 
 +
\protect % end of definitions
 +
</texcode>
 +
 
 +
=== The same example, with commentary ===
  
 
The 'key' to the keyval functionality in ConTeXt are two macros called
 
The 'key' to the keyval functionality in ConTeXt are two macros called
<cmd>getparameters</cmd> and <cmd>processaction</cmd>.
+
{{cmd|getparameters}} and {{cmd|processaction}}.
 
 
Here is a 'quickstart', assuming you want to define <tt>\MyZigzag</tt>:
 
  
 
<texcode>
 
<texcode>
 
\unprotect % enable exclamations in macro names
 
\unprotect % enable exclamations in macro names
  
\def\MyZigzag#1[#2]{%  
+
\def\MyZigzag#1[#2]{% % This brace is closed below, after the \expandafter block
 
   % the #1 makes sure we allow a space before the bracket
 
   % the #1 makes sure we allow a space before the bracket
  
Line 18: Line 85:
  
 
Now you have a set of new macros that all start with ZZ.
 
Now you have a set of new macros that all start with ZZ.
At least there are <tt>\ZZDir</tt>,<tt>\ZZLinewidth</tt>, <tt>\ZZColor</tt> and <tt>\ZZWidth</tt> (these have default values) but possibly others as well, depending on user input.
+
At least there are <tt>\ZZDir</tt>,<tt>\ZZLinewidth</tt>, <tt>\ZZColor</tt> and <tt>\ZZWidth</tt> (these have default values) but possibly others as well, depending on user input. In the next lines you make use of these variables, for example as follows:   
 
 
Here's a usage example:  
 
   
 
 
<texcode>
 
<texcode>
 
  \edef\mywidth{\ZZWidth}%
 
  \edef\mywidth{\ZZWidth}%
 
</texcode>
 
</texcode>
  
If you want to use keyword values, then you also need to use <cmd>processaction</cmd>.
+
If you want some of the variables to accept keyword values, then you also need to use {{cmd|processaction}} on the ZZ variable in question to map the keywords onto actual values.
 
 
Say you want "Dir" to be mandatory and that it accepts 4 directional keywords, as well as a direct angle specification.
 
  
I've used all mixed case keywords, because otherwise you might run into conflicts with the multilingual interface
+
Say you want "Dir" to be mandatory and that it accepts 4 directional keywords, as well as a direct angle specification. I've used all mixed case keywords, because otherwise you might run into conflicts with the multilingual interface:
  
 
<texcode>
 
<texcode>
   \expandafter\processaction\expandafter[\ZZDir]
+
   %\expandafter\processaction\expandafter[\ZZDir] % mkii
[Down       =>\def\Dir{270},
+
  \processaction[\ZZDir]                          % mkiv
Left       =>\def\Dir{180},
+
[     Down=>\def\Dir{270},
  Up         =>\def\Dir{90},
+
      Left=>\def\Dir{180},
Right     =>\def\Dir{0},
+
          Up=>\def\Dir{90},
\s!default =>\errorDir,  
+
      Right=>\def\Dir{0},
\s!unknown =>\checkDir{\ZZDir}]
+
\s!default=>\errorDir,  
 +
\s!unknown=>\checkDir{\ZZDir}]
 
} % this brace belongs to \def!
 
} % this brace belongs to \def!
 
</texcode>
 
</texcode>
Line 45: Line 108:
 
<tt>\s!default</tt> may be triggered because <tt>\ZZDir</tt>'s expansion is empty unless the user supplied something.
 
<tt>\s!default</tt> may be triggered because <tt>\ZZDir</tt>'s expansion is empty unless the user supplied something.
  
The first argument to <cmd>processaction</cmd> has to be expanded, so you need the <cmd>expandafter</cmd>s.
+
In MkII, the first argument to {{cmd|processaction}} has to be expanded, so you need the {{cmd|expandafter}}s. In MkIV, {{cmd|processaction|link=no}} does this automatically.
  
for completeness, here is an example definition of <tt>\checkDir</tt> and <tt>\errorDir</tt>:
+
For completeness, here is an example definition of <tt>\checkDir</tt> and <tt>\errorDir</tt>:
  
 
<texcode>
 
<texcode>
Line 63: Line 126:
 
\protect % end of definitions
 
\protect % end of definitions
 
</texcode>
 
</texcode>
 +
 +
[[Category:Inside ConTeXt]]

Revision as of 20:17, 26 April 2013

< Inside ConTeXt

Using Lua

There is a lovely set of functions in the utilities.parsers table that turns strings into nice Lua-accessible tables of various kinds. An example is given below; the functions are documented on the string manipulation page.

\startluacode
userdata = userdata or { }

function userdata.mycommand(keywords, keyvals) 
    keyword_options = utilities.parsers.settings_to_array(keywords)
    named_values = utilities.parsers.settings_to_hash(keyvals)
    
    -- do stuff based on that array and that hashtable.
end
\stopluacode

\def\mycommand[#1][#2]{\ctxlua{
    userdata.mycommand('#1', '#2')}    

\mycommand[top, inmargin, now][color=green, roof=gabled]

Using TeX

This section is based on a post on the mailing list by Taco Hoekwater from [2004-06-28].

Example code

\unprotect % enable exclamations in macro names

% Helper function: if the user specifies nothing, throw an error
\def\errorDir{%
   \def\Dir{0}% error recovery
   \message{Please supply "Dir" argument}%
}

% Helper function: process Dir=... other than Up/Down/Left/Right
% Accept numbers, else throw an error
\def\checkDir#1{%
  \doifnumberelse {#1}
                  {\def\Dir{#1}}
                  {\message{Invalid "Dir" argument! (#1)}}
}

% Defining our command that accepts key=val
\def\MyZigzag#1[#2]{%
  % the #1 makes sure we allow a space before the bracket

  % create commands \ZZDir, \ZZLinewidth (default 1pt), etc.
  \getparameters[ZZ][Dir=,Linewidth=1pt,Color=Red,Width=3em,#2]

  % define an alias
  \edef\mywidth{\ZZWidth}%

  % accept keywords for Dir= (and map those keywords to numbers)
  %\expandafter\processaction\expandafter[\ZZDir] % mkii
  \processaction[\ZZDir]                          % mkiv
	[      Down=>\def\Dir{270},
	       Left=>\def\Dir{180},
   	         Up=>\def\Dir{90},
 	      Right=>\def\Dir{0},
	 \s!default=>\errorDir, 
	 \s!unknown=>\checkDir{\ZZDir}]
} % this brace belongs to \def!

\protect % end of definitions

The same example, with commentary

The 'key' to the keyval functionality in ConTeXt are two macros called \getparameters and \processaction.

\unprotect % enable exclamations in macro names

\def\MyZigzag#1[#2]{% % This brace is closed below, after the \expandafter block
  % the #1 makes sure we allow a space before the bracket

  \getparameters[ZZ][Dir=,Linewidth=1pt,Color=Red,Width=3em,#2]

Now you have a set of new macros that all start with ZZ. At least there are \ZZDir,\ZZLinewidth, \ZZColor and \ZZWidth (these have default values) but possibly others as well, depending on user input. In the next lines you make use of these variables, for example as follows:

 \edef\mywidth{\ZZWidth}%

If you want some of the variables to accept keyword values, then you also need to use \processaction on the ZZ variable in question to map the keywords onto actual values.

Say you want "Dir" to be mandatory and that it accepts 4 directional keywords, as well as a direct angle specification. I've used all mixed case keywords, because otherwise you might run into conflicts with the multilingual interface:

  %\expandafter\processaction\expandafter[\ZZDir] % mkii
  \processaction[\ZZDir]                          % mkiv
	[      Down=>\def\Dir{270},
	       Left=>\def\Dir{180},
   	         Up=>\def\Dir{90},
 	      Right=>\def\Dir{0},
	 \s!default=>\errorDir, 
	 \s!unknown=>\checkDir{\ZZDir}]
} % this brace belongs to \def!

\s!default may be triggered because \ZZDir's expansion is empty unless the user supplied something.

In MkII, the first argument to \processaction has to be expanded, so you need the \expandafters. In MkIV, \processaction does this automatically.

For completeness, here is an example definition of \checkDir and \errorDir:

\def\errorDir{%
   \def\Dir{0}% error recovery
   \message{Please supply "Dir" argument}%
}

\def\checkDir#1{%
  \doifnumberelse {#1}
                  {\def\Dir{#1}}
                  {\message{Invalid "Dir" argument! (#1)}}
}

\protect % end of definitions