LATEX-L Archives

Mailing list for the LaTeX3 project

LATEX-L@LISTSERV.UNI-HEIDELBERG.DE

Options: Use Forum View

Use Monospaced Font
Show Text Part by Default
Show All Mail Headers

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

Print Reply
Subject:
From:
Joseph Wright <[log in to unmask]>
Reply To:
Mailing list for the LaTeX3 project <[log in to unmask]>
Date:
Thu, 11 Jul 2013 22:13:36 +0100
Content-Type:
text/plain
Parts/Attachments:
text/plain (181 lines)
On 10/07/2013 17:15, Jura Pintar wrote:
>> Looking at this, both Bruno and I noticed that if you are allowing a
>> clist then in principal you could simply extend \keys_set:nn to have a
>> list for the first argument. However, I'm not sure that's quite right.
>>
>> If you look at the pgfkeys demo above, what you see is that all of the
>> keys are in the same path:
>>
>>   /mymodule/key-A-i
>>   /mymodule/key-B-i
>>
>> with the family as a 'secondary path' (or something like that). This
>> means three things:
>>
>>  1) With filtering turned 'off', the keys can all be set in one
>>     operation (no need to try different places)
>>
>>  2) The key names are unique
>>
>>  3) If the key is not found, there is one place to look for an
>>     unknown handler: /mymodule/unknown
>>
>> On the other hand, the proposed extension to l3keys uses key path for
>> filtering, so we find in contrast
>>
>>  1) The keys can only all be set by actively choosing each subgroup
>>
>>  2) Key names may not be unique, so the order of subgroups becomes
>>     important
>>
>>  3) Handling for unknown keys is far from clear (do we look in
>>     /mymodule/, /mymodule/subgroup-A/, ...?)
>>
>> I'm going to take a look at how pgfkeys actually handles this.
>> --
>> Joseph Wright
> 
> 
> Yes, you're right, of course! The pgfkeys family structure is
> independent of the tree structure, and I can't remember now why I
> tried doing it based on the paths... The problems you bring up really
> should have been obvious to me. :S
> 
> Anyhow, here is a version (appended below) that does follow the
> pgfkeys approach more closely. I've not tested it very thoroughly, but
> it seems to work... Again, I'm sure there's much room for improvement!
> 
> There are two new properties:
> 
> 1) .filter:     - defines a key as a filter
> 2) .filters:n  - takes a clist argument that specifies which filters
> are to be applied to a key (this is unlike the pgfkeys '.belongs to
> family' handler, which only accepts a single family key)
> 
> And there are several new public commands:
> 
> 1) \keys_filters_activate:nn  {<module>} {<filter clist>}
> 2) \keys_filters_deactivate:nn  {<module>} {<filter clist>}
> 3) \keys_filters_deactivate_all:
> 4) \keys_set_filtered:nn {<module>} {<keyval list>}
> 5) \keys_set_known_filtered:nnN {<module>} {<keyval list>} <clist>
> 
> and a couple of public variables
> 
> \l_keys_filtered_seq  - which contains the keys that were filtered out
> on the last call of \keys_set_filtered:nn
> \l_active_filters_seq  - which contains the filter keys currently activated
> 
> A key will be filtered out if any of the filters that apply to it are
> active, and keys with no filters applied will be set normally.

The pgfkeys approach seems perhaps more complex than needed to deal with
the concept of groups of keys. I suspect that's because pgfkeys aims to
allow basically full programming using keys: the target of l3keys is
more limited. (I still need to read over the code in pgfkeys to pick up
why they do these more complex things.)

Looks at what seems to be needed, an ('opt-in') interface such as

  \keys_define:nn { module }
    {
      key-one .code:n  = { \tl_show:n { key-one } },
      key-one .group:n = { a },
      key-two .code:n  = { \tl_show:n { key-two } },
    }
  \keys_set_grouped:nnn { module } { a }
    { key-one = value , key-two = value }

is not unreasonable. This allows each key to be in exactly one group:
doing multiple groups is possible but more tricky. (Code follows a bit
later.) My thinking with this is that you can simply do a 'filtered' or
'grouped' setting without having to track when filtering is on/off.

The above interface leaves open a few questions:

 - How is nesting handled? Does \keys_set:nn within
   \keys_set_grouped:nnn respect groups? Does
   \keys_set_grouped:nnn within \keys_set_grouped:nnn
   work in a union or intersection way?

 - Do unknown keys raise an error, or are they ignored as they
   are not in any group?

Quick implementation: won't be the final one if we go for this! (Some of
it depends on those questions.)

\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\cs_set_protected:Npn \__keys_cmd_set:n #1
  {
    \tl_clear_new:c { \c__keys_vars_root_tl #1 .default }
    \tl_set:cn { \c__keys_vars_root_tl #1 .default } { \q_no_value }
    \tl_clear_new:c { \c__keys_vars_root_tl #1 .group }
    \clist_set:cn { \c__keys_vars_root_tl #1 .group } { }
    \tl_clear_new:c { \c__keys_vars_root_tl #1 .req }
  }
\cs_new_protected:Npn \__keys_groups_set:n #1
  { \tl_set:cn { \c__keys_vars_root_tl \l_keys_path_tl .group } {#1} }
\cs_new_protected:cpn { \c__keys_props_root_tl .group:n } #1
  { \__keys_groups_set:n {#1} }
\tl_new:N \l__keys_groups_clist
\cs_new_protected:Npn \keys_set_grouped:nnn
  { \__keys_set_grouped:oonnn { \l__keys_module_tl } {
\l__keys_groups_clist } }
\cs_new_protected:Npn \__keys_set_grouped:nnnnn #1#2#3#4#5
  {
    \tl_set:Nx \l__keys_module_tl { \tl_to_str:n {#3} }
    \tl_set:Nx \l__keys_groups_clist { #4 }
    \keyval_parse:NNn \__keys_set_elt:n \__keys_set_elt:nn {#5}
    \tl_set:Nn \l__keys_module_tl {#1}
    \tl_set:Nn \l__keys_groups_clist {#2}
  }
\cs_generate_variant:Nn \__keys_set_grouped:nnnnn { oo }
\cs_set_protected:Npn \__keys_set_elt_aux:nn #1#2
  {
    \tl_set:Nx \l_keys_key_tl { \tl_to_str:n {#1} }
    \tl_set:Nx \l_keys_path_tl { \l__keys_module_tl / \l_keys_key_tl }
    \__keys_value_or_default:n {#2}
    \clist_if_empty:NTF \l__keys_groups_clist
      { \__keys_set_elt_aux: }
      { \__keys_set_elt_grouped: }
  }
\cs_new_protected_nopar:Npn \__keys_set_elt_aux:
  {
    \bool_if:nTF
      {
        \__keys_if_value_p:n { required } &&
        \l__keys_no_value_bool
      }
      {
        \__msg_kernel_error:nnx { kernel } { value-required }
          { \l_keys_path_tl }
      }
      {
        \bool_if:nTF
          {
              \__keys_if_value_p:n { forbidden } &&
            ! \l__keys_no_value_bool
          }
          {
            \__msg_kernel_error:nnxx { kernel } { value-forbidden }
              { \l_keys_path_tl } { \l_keys_value_tl }
          }
          { \__keys_execute: }
      }
  }
\cs_new_protected_nopar:Npn \__keys_set_elt_grouped:
  {
    \cs_if_exist:cT { \c__keys_vars_root_tl \l_keys_path_tl .group }
      {
        \clist_if_in:NvT
          \l__keys_groups_clist
          { \c__keys_vars_root_tl \l_keys_path_tl .group }
          { \__keys_set_elt_aux: }
      }
  }
\cs_generate_variant:Nn \clist_if_in:NnT { Nv }
-- 
Joseph Wright

ATOM RSS1 RSS2