LATEX-L Archives

Mailing list for the LaTeX3 project

LATEX-L@LISTSERV.UNI-HEIDELBERG.DE

Options: Use Classic View

Use Monospaced Font
Show Text Part by Default
Condense Mail Headers

Topic: [<< First] [< Prev] [Next >] [Last >>]

Print Reply
Content-Transfer-Encoding: 8bit
Sender: Mailing list for the LaTeX3 project <[log in to unmask]>
From: Javier Múgica de Rivera <[log in to unmask]>
Date: Sun, 22 Oct 2006 23:49:44 +0200
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
MIME-Version: 1.0
Reply-To: Mailing list for the LaTeX3 project <[log in to unmask]>
Parts/Attachments: text/plain (215 lines)
Some months ago I pointed out in another message that I wanted to make 
some remarks about templates. Well, we all know the pace of this list, 
where months play the rôle of days, so here it is:

There is something about how collections work that puzzles me. 
Currently, if one wishes to use the instance "iname" of the type "type", 
one has to write

\UseInstance{type}{iname},

no matter whether the instance was declared via \DeclareInstance or via 
\DeclareCollectionInstance. So, ¿what are the collections for? I know, 
to restrict the use of an instance to a particular collection.

Form my point of view the existence of instances should be independent 
from the association of particular instances with certain collections. 
Thus, a file may store the declaration of a bunch of instances for a 
particular template, say, for a heading formating template. Supose they 
are called ''simple", "beautiful", "front1", "front2", where the names 
of the last ones suggest that they are specifically designed to be used 
in front matters. And suppose that for a particular work or in a 
particular series of books the designer decides to make use of the 
instance "front1" to format the headings at the frontmatter. Then he may 
write

\AssociateInstanceCollection{heading}{frontmatter}{front1},

and at some point in the document near the beginning the author or, more 
likely, a macro defined by the designer, writes

\UseCollection{heading}{frontmatter},

so that from now on (normal scoping rules) the instance to be used to 
format headings is the corresponding to the collection frontmatter. An 
so when the time comes to create a heading (posibly inside another 
macro) one simply writes

\UseInstance{heading}{},

where the empty second argument means: "Use the instance that is in 
force for the type heading", and an error is issued if such an instance 
doesn't exist, i.e., if there has not been a previous call to 
\UseCollection where the first argument is "heading" and also a suitable 
call to \AssociateInstanceCollection. This allows the creation of very 
simple high level commands. Think for example about formating a caption. 
One may simply use always \UseInstance{caption}{}, and the setting of 
the collection in force will be made by the commands that format the 
particular float: figures, tables, pieces of code,... Thus, once the 
skeleton is written, a separate format-defining file will consist of 
severall calls to \AssociateInstanceCollection{type}{collection}{iname} 
(among other tings), setting the appearance of the documment.

Furthermore, one could write

\SetCollection{frontamtter}

in order to set in force all the instances of all types that have been 
associated to the collection.


I think it wouldn't be very difficult to implement this. At the present 
time the command that gets executed when \UseInstance is called is

\<coll>type/iname,

wher "coll" may be empty. We can have simply \type/iname. The definition 
of \AssociateInstanceCollection would then be:

\def\AssociateInstanceCollection#1#2#3{    % type, collection, iname
  \let:cc{#1/??_#2}{#1/#3}
}

Where it can be seen that ??_coll is a faked iname that gets assigned to 
a real iname via \AssociateInstanceCollection.
The code for \UseCollection is then

\def\UseCollection#1#2{    % type, collection
  \let:cc{#1/???}{#1/??_#2}
}

And so type/??? means "current iname according to the collection in 
force for this type". This definition needs a check to test if  
\type/??_coll has been associated to a real iname, and if not issue an 
error or define \type/??_coll to issue an error. This last option allows 
the association to take place latter, since \UseCollection may appear in 
the definition of a macro that expects the association to be performed 
before the macro is called. It will also complicate the initial check 
for \type/??_coll, but see below.

We need also, at the moment of declaring a type, to define \type/??? to 
issue an error. If we do not the user will get the error "the instance 
??? for type heading is not defined", or something like that.

The command \SetCollection executes, if it is defined, 
\TP_tlp_set_collection_coll (coll is #1):

\def:Npn\SetCollection#1{
  \cs:w TP_tlp_set_collection_#1\cs_end:
}

\TP_tlp_set_collection_coll will get dinamically defined by adding code 
to it every time we call \AssociateInstanceCollection. We have then to 
modify the previous definition of this macro. It may also be useful to 
know which instance is associated to a particular collection, if any. In 
particular, it is necesary for the check needed at \SetCollection:
 
\def:Npn\AssociateInstanceCollection#1#2#3{    % type, collection, iname
  \let:cc{#1/??_#2}{#1/#3}

  %Here we localy (important) add the command \UseCollection{#1}{#2} to 
de definition of \TP_tlp_set_collection_coll
  \tlp_put_right:cn{TP_tlp_set_collection_#2}{\UseCollection{#1}{#2}}

  %Record that type+collection is from now on iname:
  \def:cpn{TPC>/#1/#2}{#3}        %Note the order #1/#2. We always 
regard a collection as an indirect iname for types.
}

And the definition of \UseCollection will then be:

\def:Npn\UseCollection#1#2{    % type, collection
  \expandafter\ifx\csname TPC>/#1/#2\endcsname\relax    %define #1/??_#2 
to be an error message
    \def:cpn{#1/??_2}{PackageError{template}{There is not defined any 
instance of type #1 to be used with the collection #2}}
  \else
    \let:cc{#1/???}{#1/??_#2}
  \fi
}

We need also to modify slightly the definition of UseInstance to check 
if the second argument is empty, and if so execute \type/??? (i.e. 
\#1/???) instead of \type/iname (\#1/#2).

It is important that the list TP_tlp_set_collection_coll (for every 
particular coll) be updated locally, as the collection in force is also 
associated locally. It works properly because \UseCollection{type}{coll} 
is appended to the right, so that local settings override those from an 
outer scope. We cannot provide a global \gAssociateInstanceCollection, 
since a global setting of TP_tlp_set_collection_coll will play havoc on 
the other types. (We can make a really ugly hack, by executing 
\globalhack_TP_type_coll, defined as

{\tlp_put_right:cn{TP_tlp_set_collection_coll}{\UseCollection{type}{coll}}\aftergroup\globalhack_TP_type_coll},

where type and coll are parameters #1 and #2, but this does not seem the 
right solution).
The right solution is to make TP_tlp_set_collection_coll consist of 
several tlp! So that TP_tlp_set_collection_front could be for example

{\TP_tlp_set_collection_front_heading\TP_tlp_set_collection_front_foot\TP_tlp_set_collection_front_chapter}

Each of the individual tlp's is really a stak, where inner associations 
get added to the left and thus override outer ones. The final definition 
of \AssociateInstanceCollection is then:

\def:Npn\AssociateInstanceCollection#1#2#3{    % type, collection, iname
  \let:cc{#1/??_#2}{#1/#3}

  %The following line is pseudocode. It doesn't seem to be difficult to 
translate into code,
  %but this is the first time I use a tlp or any of its relatives (I 
can't even remember which kinds of structures exsit),
  %so I didn't bother to look in the manual for the functions that I need.
  look if \cs:w TP_tlp_set_collection_#2_#1\end_cs: appears in \cs:w 
TP_tlp_set_collection_#2\end_cs:    %Assume the real function is of type TF
  {
    
\tlp_gput_right:cc{TP_tlp_set_collection_#2}{TP_tlp_set_collection_#2_#1}   
 %Make it global so that we insert it once and for ever
    \gdef:cn{TP_tlp_set_collection_#2_#1}{}
  }
  {}
  \tlp_put_right:cn{TP_tlp_set_collection_#2_#1}{\UseCollection{#1}{#2}}

  %Record that type+collection is from now on iname:
  \def:cpn{TPC>/#1/#2}{#3}        %Note the order #1/#2. We always 
regard a collection as an indirect iname for types.
}

This new definition of \AssociateInstanceCollection needs 
TP_tlp_set_collection_coll to exist, so we may either add a check and 
create it if necessary, or define
\DeclareCollection#1{ \tlp_new:cn{TP_tlp_set_collection_#1}{}.

A global version of \AssociateInstanceCollection is now trivial:

\def:Npn\AssociateInstanceCollection#1#2#3{    % type, collection, iname
  \glet:cc{#1/??_#2}{#1/#3}

  look if \cs:w TP_tlp_set_collection_#2_#1\end_cs: appears in \cs:w 
TP_tlp_set_collection_#2\end_cs:    %Assume the real function is of type TF
  {
    
\tlp_gput_right:cc{TP_tlp_set_collection_#2}{TP_tlp_set_collection_#2_#1}
  }
  {}
  \gdef:cn{TP_tlp_set_collection_#2_#1}{\UseCollection{#1}{#2}}

  \gdef:cpn{TPC>/#1/#2}{#3}
}

Successive calls to  \AssociateInstanceCollection within the same group 
will keep unnecessary \UseCollection{type}{coll}, but I think it is not 
a problem in practice, and in order to eliminate them we should know 
whether the last \UseCollection{type}{coll} of 
TP_tlp_set_collection_coll_type comes from the current gruop or from an 
outer one, which seem awckward.

And that's all!
If all of the above is useless, do not feel sympathy whith me! I really 
needed to unrust myself, its a long time since I last worked with TeX.

Javier A.

ATOM RSS1 RSS2