Received: from mout.gmx.net (mout.gmx.net [212.227.15.15]) by h1439878.stratoserver.net (8.14.2/8.14.2/Debian-2build1) with ESMTP id r6AGK16o014322 for ; Wed, 10 Jul 2013 18:20:02 +0200 Received: from relay2.uni-heidelberg.de ([129.206.210.211]) by mx-ha.gmx.net (mxgmx113) with ESMTP (Nemesis) id 0MHc5g-1UteGV42LE-003Kr0 for ; Wed, 10 Jul 2013 18:19:56 +0200 Received: from listserv.uni-heidelberg.de (listserv.uni-heidelberg.de [129.206.100.94]) by relay2.uni-heidelberg.de (8.13.8/8.13.8) with ESMTP id r6AGGAPr027342 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 10 Jul 2013 18:16:11 +0200 Received: from listserv.uni-heidelberg.de (listserv.uni-heidelberg.de [127.0.0.1]) by listserv.uni-heidelberg.de (8.13.8/8.13.8) with ESMTP id r6ADaOP3013743; Wed, 10 Jul 2013 18:16:10 +0200 Received: by LISTSERV.UNI-HEIDELBERG.DE (LISTSERV-TCP/IP release 16.0) with spool id 10299840 for LATEX-L@LISTSERV.UNI-HEIDELBERG.DE; Wed, 10 Jul 2013 18:16:10 +0200 Received: from relay.uni-heidelberg.de (relay.uni-heidelberg.de [129.206.100.212]) by listserv.uni-heidelberg.de (8.13.8/8.13.8) with ESMTP id r6AGG9Cm025489 for ; Wed, 10 Jul 2013 18:16:09 +0200 Received: from mail-vc0-f174.google.com (mail-vc0-f174.google.com [209.85.220.174]) by relay.uni-heidelberg.de (8.14.1/8.14.1) with ESMTP id r6AGFvAE016834 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=FAIL) for ; Wed, 10 Jul 2013 18:16:01 +0200 Received: by mail-vc0-f174.google.com with SMTP id kw10so5719973vcb.19 for ; Wed, 10 Jul 2013 09:15:57 -0700 (PDT) MIME-Version: 1.0 X-Received: by 10.58.234.161 with SMTP id uf1mr19146964vec.57.1373472957653; Wed, 10 Jul 2013 09:15:57 -0700 (PDT) Received: by 10.52.27.47 with HTTP; Wed, 10 Jul 2013 09:15:57 -0700 (PDT) References: <51C94FA0.1080803@morningstar2.co.uk> <51DD0EBD.6080308@morningstar2.co.uk> Content-Type: text/plain; charset=windows-1252 X-MIME-Autoconverted: from quoted-printable to 8bit by listserv.uni-heidelberg.de id r6AGG9Cm025490 Message-ID: Date: Wed, 10 Jul 2013 12:15:57 -0400 Reply-To: Mailing list for the LaTeX3 project Sender: Mailing list for the LaTeX3 project From: Jura Pintar Subject: Re: l3keys feature request To: LATEX-L@LISTSERV.UNI-HEIDELBERG.DE In-Reply-To: <51DD0EBD.6080308@morningstar2.co.uk> Precedence: list List-Help: , List-Unsubscribe: List-Subscribe: List-Owner: List-Archive: Content-Transfer-Encoding: quoted-printable X-MIME-Autoconverted: from 8bit to quoted-printable by relay2.uni-heidelberg.de id r6AGGAPr027342 Envelope-To: X-GMX-Antispam: 0 (Mail was not recognized as spam); Detail=V3; X-GMX-Antivirus: 0 (no virus found) X-UI-Filterresults: notjunk:1;V01:K0:7Jzj8nDyc0M=:SeGfco0humhlXDeeDi8jEx VeMTHMpDofDKhrltLncqoSeLlhH+54r/7PbCLpOmJONzqWq9zDQZ576HDdP37fxE1azO06j TfwI2Ba0DVd0Kbmovjc24ICmgXVSJfpNXZ/gnLRdtCvqB9W4Fa2nxd6rcGo/1emF7iSn8NU 9hz8TGHSRh5Zo1xTevmljfdp7VqpefYCh3P5aCUUglvSTjLGInauSk3jIvduN4DytvlG1ZB 9ru5pntAnb/4aS7jo924Fjt5SI6gbuje12L2o1Pk0h69vXFwyNRmdE/0qT4hIrVoDL4fxMQ 1H4LkFo3qOV2rBb4fft3Kc3x/JGNdt4HvP/bIbmaF0TfmVy4jX8XaPXuvRd+Z59Q4QrLft3 7Ol4Oby/gql3wZvqWOs2kctXDjjxoTYyS59gunLEc6XitRx26JeDsfzH1HMw9bvi+YKDjFG TuxV6Ok+M44I3qZQ+wazfSyIrfXBhzAmoQdc07ILoH4ShIMICx5Ggz/XELAcnwywl0vYle3 BGbeXdZ8hN+bQ+x954swHjgx9mQtAiQ4RkaflWYBhKl8RJ/CICtIF311ksOG3bkV6b7BkVR QqNbB+Wlvw22DXfRuLfUSNjblwmuylqtdE9z+EsSnfD7KzBVyyEnxvUNGqow6j+oQdUpO8T TcxA570bXKY0Pkf+/mT65pwZoT4H9gtJGhN9KdJVu4uuUogcaJG+k2YAILCfGpZLEDkVIXk 9YYFOtmdtf7AeCCqxfQ+oZR9TsdNbBfHxBqVoFwhOdGIy/xRgzBTziWiIuCF5StadFo6F+2 Figns+xYKLcbYZsynTE+PlL0HPZ7/SipRe37glGGsa+Bmkx85TslLRAgKrEc/d9IyTfpbK6 QnSKy2vEFyJ56rPDfGMXpDi0h3Ij2+ZDQMmO8+Wi8sfkfw8G4dYNzx3kKPq7DGyTP9RbX9G yru+WAeP0sefTCJnbyJQ1qstXSqs2gla8Z+LGjN0GjZyF2HYjBoYhZoNbFmgCfCrUyqRDB/ CqW7jel5NZTS3CpRgBJs0nuMimxc83svI5F8WU4YeOk8DWchMblR2E9zaJ+4rYmG6exUzOE GdTuHe1CjNGnTfNeF6ECMZH9e7RB1WbbgxLVrg9W3HUNrFNH6Rv00I1lthK4Pw5hov6YGjw rKiDXF91gq1vfxvg7xEa0voCTYFUEtC9cAomejQzIUd5sTZzz4cWTrv31B3yWaPJV7bXGTl CHwIAWBVz3aYZkBg5Rfr6rrw93W4MHL3NVipUtFnEPBCRPzaGSAafinCOubdnV5mZN5gajf m319UjwW+uGHcXkKUCChLWte5AfPff4R8OMPyniwoxT6DaQulDcnlGbYzkkhS8IWMSb26Jn /oVcbhn1WqxtsFgJDszP0v64gXvOk3AA6xMnCFeg7DC3lUE7ty8Y6zy0xdHiFQfYyettIxT IvagtdqdPCMVffPrxqjsKOnDL46CVPY/LMH/A0t5CsBMhRQIRxi80LReiQRiNBkV+qGCz6M t+lrZ3v0udKrpsjhUppo6h2bc8YvGlMwKogJ3T+5k5eBEpnWgfX0h2jL4ayU5E9kNlpWpfV bKfLOORTLIBGmSnyy6/sF6v9EOOVfSBneBrXgXHba5UEPr0uLsEW/TelqnQ= X-UI-Loop:V01:3EPKJTrAKLM=:vI72AsvRgl6sC2u0YMgrn8KX5r4jK07inVO76ISwXno= Status: R X-Status: X-Keywords: X-UID: 7231 > 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 {} {} 2) \keys_filters_deactivate:nn {} {} 3) \keys_filters_deactivate_all: 4) \keys_set_filtered:nn {} {} 5) \keys_set_known_filtered:nnN {} {} 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 activat= ed 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. \bool_new:N \l__key_filtered_bool \clist_new:N \l__key_filters_clist \prop_new:N \l__filter_states_prop \prop_new:N \l__keys_filters_prop \seq_new:N \l_keys_filtered_seq \seq_new:N \l_active_filters_seq \seq_new:N \l__active_filters_seq \cs_generate_variant:Nn \__msg_kernel_error:nnnnn { nnoVV } \cs_generate_variant:Nn \keys_define:nn { Vo } \cs_generate_variant:Nn \keys_if_exist:nnTF { VnTF } \cs_generate_variant:Nn \keys_set:nn { Vn } \cs_generate_variant:Nn \keys_set_known:nnN { VnN } \cs_generate_variant:Nn \prop_get:NnN { NxN } \cs_generate_variant:Nn \tl_if_eq:nnT { VnT } \cs_new_protected:Npn \__keys_filter_define: { \prop_if_in:NnF \l__filter_states_prop { \l_keys_path_tl } { \prop_put:NVn \l__filter_states_prop \l_keys_path_tl { 0 } } } \cs_new_protected:Npn \__keys_filters_set:n #1 { \clist_clear:N \l__key_filters_clist \clist_map_inline:nn {#1} { \prop_if_in:NoTF \l__filter_states_prop { \l__keys_module_tl / ##= 1 } { \clist_put_right:No \l__key_filters_clist { \l__keys_module_tl / ##1 } } { \__msg_kernel_error:nnoVV { kernel } { invalid-filter } { \l__keys_module_tl / ##1 } \l_keys_path_tl \l__keys_modul= e_tl } } \clist_if_empty:NF \l__valid_filters_clist { \prop_put:NVV \l__keys_filters_prop \l_keys_path_tl \l__key_filters_clist } } \cs_new_protected:cpn { \c__keys_props_root_tl .filter: } { \__keys_filter_define: } \cs_new_protected:cpn { \c__keys_props_root_tl .filters:n } #1 { \__keys_filters_set:n {#1} } \cs_new_protected:Npn \keys_filters_activate:nn #1#2 { \clist_map_inline:nn {#2} { \prop_if_in:NnTF \l__filter_states_prop { #1 / ##1 } { \prop_put:Nnn \l__filter_states_prop { #1 / ##1 } { 1 } \seq_put_right:Nn \l__active_filters_seq { #1 / ##1 } } { \__msg_kernel_error:nnnn { kernel } { unknown-filter } { #1 / ##1 } {#1} } } \seq_set_eq:NN \l_active_filters_seq \l__active_filters_seq } \cs_new_protected:Npn \keys_filters_deactivate:nn #1#2 { \clist_map_inline:nn {#2} { \prop_if_in:NnTF \l__filter_states_prop { #1 / ##1 } { \prop_put:Nnn \l__filter_states_prop { #1 / ##1 } { 0 } \seq_remove_all:Nn \l__active_filters_seq { #1 / ##1 } } { \__msg_kernel_error:nnnn { kernel } { unknown-filter } { #1 / ##1 } {#1} } } \seq_set_eq:NN \l_active_filters_seq \l__active_filters_seq } \cs_new_protected:Npn \keys_filters_deactivate_all: { \seq_map_inline:Nn \l__active_filters_seq { \prop_put:Nnn \l__filter_states_prop {##1} { 0 } } \seq_clear:N \l__active_filters_seq \seq_set_eq:NN \l_active_filters_seq \l__active_filters_seq } \cs_new_protected:Npn \keys_set_filtered:nn #1#2 { \seq_clear:N \l_keys_filtered_seq \tl_set:Nn \l__keys_module_tl {#1} \keyval_parse:NNn \__keys_set_filtered:n \__keys_set_filtered:nn {#2} } \cs_new_protected:Npn \__keys_set_filtered:n #1 { \prop_get:NoNTF \l__keys_filters_prop { \l__keys_module_tl / #1 } \l__key_filters_clist { \bool_set_false:N \l__key_filtered_bool \clist_map_inline:Nn \l__key_filters_clist { \prop_get:NnN \l__filter_states_prop {##1} \l__tmpa_tl \tl_if_eq:VnT \l__tmpa_tl { 1 } { \bool_set_true:N \l__key_filtered_bool \clist_map_break: } } \bool_if:NTF \l__key_filtered_bool { \seq_put_right:Nn \l_keys_filtered_seq {#1} } { \keys_set:Vn \l__keys_module_tl {#1} } } { \keys_set:Vn \l__keys_module_tl {#1} } } \cs_new_protected:Npn \__keys_set_filtered:nn #1#2 { \prop_get:NoNTF \l__keys_filters_prop { \l__keys_module_tl / #1 } \l__key_filters_clist { \bool_set_false:N \l__key_filtered_bool \clist_map_inline:Nn \l__key_filters_clist { \prop_get:NnN \l__filter_states_prop {##1} \l__tmpa_tl \tl_if_eq:VnT \l__tmpa_tl { 1 } { \bool_set_true:N \l__key_filtered_bool \clist_map_break: } } \bool_if:NTF \l__key_filtered_bool { \seq_put_right:Nn \l_keys_filtered_seq { #1 =3D #2 } } { \keys_set:Vn \l__keys_module_tl { #1 =3D #2 } } } { \keys_set:Vn \l__keys_module_tl { #1 =3D #2 } } } \cs_new_protected:Npn \keys_set_known_filtered:nnN #1#2#3 { \seq_clear:N \l_keys_filtered_seq \clist_clear:N \l__tmpa_clist \clist_clear:N \l__tmpb_clist \tl_set:Nn \l__keys_module_tl {#1} \keyval_parse:NNn \__keys_set_known_filtered:n \__keys_set_known_filtered:nn {#2} \clist_concat:NNN #3 \l__tmpa_clist \l__tmpb_clist } \cs_new_protected:Npn \__keys_set_known_filtered:n #1 { \prop_get:NoNTF \l__keys_filters_prop { \l__keys_module_tl / #1 } \l__key_filters_clist { \bool_set_false:N \l__key_filtered_bool \clist_map_inline:Nn \l__key_filters_clist { \prop_get:NnN \l__filter_states_prop {##1} \l__tmpa_tl \tl_if_eq:VnT \l__tmpa_tl { 1 } { \bool_set_true:N \l__key_filtered_bool \clist_map_break: } } \bool_if:NTF \l__key_filtered_bool { \seq_put_right:Nn \l_keys_filtered_seq {#1} } { \keys_set_known:VnN \l__keys_module_tl {#1} \l__tmpa_clist } } { \keys_set_known:VnN \l__keys_module_tl {#1} \l__tmpa_clist } } \cs_new_protected:Npn \__keys_set_known_filtered:nn #1#2 { \prop_get:NoNTF \l__keys_filters_prop { \l__keys_module_tl / #1 } \l__key_filters_clist { \bool_set_false:N \l__key_filtered_bool \clist_map_inline:Nn \l__key_filters_clist { \prop_get:NnN \l__filter_states_prop {##1} \l__tmpa_tl \tl_if_eq:VnT \l__tmpa_tl { 1 } { \bool_set_true:N \l__key_filtered_bool \clist_map_break: } } \bool_if:NTF \l__key_filtered_bool { \seq_put_right:Nn \l_keys_filtered_seq { #1 =3D #2 } } { \keys_set_known:VnN \l__keys_module_tl { #1 =3D #2 } \l__tmpb= _clist } } { \keys_set_known:VnN \l__keys_module_tl { #1 =3D #2 } \l__tmpb_cli= st } } \__msg_kernel_new:nnnn { kernel } { invalid-filter } { The~filter~'#1'~does~not~exist~and~will~not~be~applied~to~key~'#2'. } { Filter~=92#1=92~has~not~been~defined~for~the~module~'#3'.\\ A~filter~must~be~defined~using~the~.filter:~property~ before~it~can~be~applied~to~any~keys. } \__msg_kernel_new:nnnn { kernel } { unknown-filter } { The~filter~'#1'~is~not~defined.~It~cannot~be~activated~or~deactivated= . } { Filter~=92#1=92~has~not~been~defined~for~the~module~'#2'.\\ A~filter~must~be~defined~using~the~.filter:~property~ before~it~can~be~applied. } By the way, the syntax and function of my initially proposed \keys_subgroups_set:nnn could be roughly captured by the following code (though I doubt it would add anything useful any more) \cs_new_protected:Npn \keys_subgroups_set:nnn #1#2#3 { \prop_set_eq:NN \l__tmpa_prop \l__filter_states_prop \keys_filters_deactivate_all: \keys_filters_activate:nn {#1} {#2} \keys_set_filtered:nn {#1} {#3} \prop_set_eq:NN \l__filter_states_prop \l__tmpa_prop } \cs_new_protected:Npn \keys_subgroups_set_known:nnn #1#2#3 { \prop_set_eq:NN \l__tmpa_prop \l__filter_states_prop \keys_filters_deactivate_all: \keys_filters_activate:nn {#1} {#2} \keys_set_known_filtered:nn {#1} {#3} \prop_set_eq:NN \l__filter_states_prop \l__tmpa_prop }