Received: from mout.gmx.net (mout.gmx.net [212.227.17.21]) by h1439878.stratoserver.net (8.14.2/8.14.2/Debian-2build1) with ESMTP id r6D9q5Ym005695 for ; Sat, 13 Jul 2013 11:52:06 +0200 Received: from relay.uni-heidelberg.de ([129.206.100.212]) by mx-ha.gmx.net (mxgmx110) with ESMTP (Nemesis) id 0Llpue-1UOsn83grQ-00ZR7H for ; Sat, 13 Jul 2013 11:51:59 +0200 Received: from listserv.uni-heidelberg.de (listserv.uni-heidelberg.de [129.206.100.94]) by relay.uni-heidelberg.de (8.14.1/8.14.1) with ESMTP id r6D9n8Ag009446 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Sat, 13 Jul 2013 11:49:08 +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 r6D6MeCd025215; Sat, 13 Jul 2013 11:49:07 +0200 Received: by LISTSERV.UNI-HEIDELBERG.DE (LISTSERV-TCP/IP release 16.0) with spool id 10267359 for LATEX-L@LISTSERV.UNI-HEIDELBERG.DE; Sat, 13 Jul 2013 11:49:07 +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 r6D9d6AF002404 for ; Sat, 13 Jul 2013 11:39:06 +0200 Received: from mail-wg0-f45.google.com (mail-wg0-f45.google.com [74.125.82.45]) by relay.uni-heidelberg.de (8.14.1/8.14.1) with ESMTP id r6D9ctqw007730 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=FAIL) for ; Sat, 13 Jul 2013 11:38:58 +0200 Received: by mail-wg0-f45.google.com with SMTP id j13so9023877wgh.24 for ; Sat, 13 Jul 2013 02:38:55 -0700 (PDT) X-Received: by 10.194.110.6 with SMTP id hw6mr26758441wjb.3.1373708335532; Sat, 13 Jul 2013 02:38:55 -0700 (PDT) Received: from palladium.home (host86-185-181-102.range86-185.btcentralplus.com. [86.185.181.102]) by mx.google.com with ESMTPSA id d8sm7832916wiz.0.2013.07.13.02.38.53 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sat, 13 Jul 2013 02:38:54 -0700 (PDT) User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:17.0) Gecko/20130620 Thunderbird/17.0.7 MIME-Version: 1.0 References: <51C94FA0.1080803@morningstar2.co.uk> <51DD0EBD.6080308@morningstar2.co.uk> <51DF2000.30703@morningstar2.co.uk> X-Enigmail-Version: 1.5.1 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Message-ID: <51E12031.4060600@morningstar2.co.uk> Date: Sat, 13 Jul 2013 10:38:57 +0100 Reply-To: Mailing list for the LaTeX3 project Sender: Mailing list for the LaTeX3 project From: Joseph Wright Subject: Re: l3keys feature request To: LATEX-L@LISTSERV.UNI-HEIDELBERG.DE In-Reply-To: Precedence: list List-Help: , List-Unsubscribe: List-Subscribe: List-Owner: List-Archive: 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:L12uVQzt1e4=:KrCdJtN/gmjs+L56VUkeyL tNphtRIamdFbghSp0XeS4XbbnKBw823XPGWX5FFLsqxul7xm/IiwNsO8WWfZVL7Olgyolw9 FY1uQbKoECy+1UaC0Q3SME88vumfg96N5gpAJPk62+HhI+RLYdqDM+Ymyicws23IDbfpXgd yQ5NKUUwCiNwUOhUbr44A09jzoNz1bnmiJkrNuook79szXL+LY7OMLQb66MBaiZi7c8P2Ri 4kK10/AKzMTsWsg7NFP3EGoQR/nYGJU4jNtMjHBMUXwGqO0cz6osU5BgMWQBTTbyyTfHriV PK/xhYQ7a2S45KZLSvjBvT9F2qBjt1kx3e9qj+kmxRKUitlXOQ5Fa2WsBdOtqMTroYIVMTN IgaWOiK4+4EksjvobsWVh+pqgKybTzZloUILHHlpaMzUA3sJAC7h3rqR3vHi6mZrmKnsjgP vtED/qLlJEq/7eTp0KCKYER5IpuGGFbMrbJZR42COKBZyf/nPFOQbT3da2FozAS5HmIAF5p nCiOEKXALv+Han4uU4DyPs7NkG1RFtVp0Lqtgzy0Ndne+8ixduFSL8OGqhc+/Fd6eEHZ2Qt uzlrePZ7mjEv2fjhJpwfovz2GMNaDl/4DlZzIJlAkG+FSLU8fTsNgV1FlWo4MdaLwTmFFE5 E7vU4K3+1sqkEmbUMKTEJO6n668VGD/QqYjw9JUeBgJhXjOIfBg3opFBdIpM35MzBSzhPoN smsqfl76nPWtK4TBROxR1umr7vIltg6J1ZIMzFaxGE1aevDEtVr1+G6Vaf2JZ0JcUN3san9 GEXalBx6sLP6e+2neHMHIxrZ7KC00wgG6KGY7iHFGMJUFr2SF6DU4xzXb5pB37YNEjMSfY0 96a481vlcgCJ3cKiy13A28GM15ao3niMsPOJcjp9wCs9+D2oYi932Hq1T5h+LxJ2VnTeUqY fX6kju1RD7+B6TLXvZ4bS3Y5ga57ZFjnDdvY8T/IoCgefUd8s2ODjhFZi1WsUzpqR7lMjLa tkhDbRyfNLe4fd5N5LYndMHeIdTDGfgNQfMkmw4VUogPI+Juw3d8HwZ6T80DDkm47J3uoit UbiB9mlUNAtqwFe8SVrMwZeY3WUj8ub6RLFQNYduglzS3ftyroXPZxGZNBe+SoRUf565ENg G112uk3BVfh2esi0V4+K03NRzXZPONhKgUReBEBh9+oJsUVazYXgmSrG2aIqYlXv4k9RPqb WIHlO3PGweVSeGVnkGE/xzzdj4WAq3V1mN9q6N2Yy/BJ3imUBd//BCM3MpWviQWN2ZGvHlG d46kt+F9xadNH0oZyEhkUNQSEVLt3MJ6qPTOkO/I2TRXwEzoy1fDehxLeaeJOUh1OqVpIDT sTFFnW2EAGfP3EhDLr24IX/51wns5BgTrF4bISe1HDYesNf4DZmzUfU9rR3bfHSG/q+Z8X5 sEqgcE1RLxJa9tdablmqWUZjJZdR+N6igf6+YFNATRKiWT7LtyFa8rr+a/FbtZoyDnzXO1k U9gUL1Svw6wEiprO8TnnNSxxamn+tepmw3J2NWBubQptYue0k+w85E9H4Q++9aTT2UFqou0 EBDbx8xqYNuqom5LxR2ApOU/JQH0BKDBd/o7hdiucPz85Ns50+l8mZwqDN09VurOJ7ccWjr 8cTMLWHfb X-UI-Loop:V01:VMJsrrVKsNU=:jIlGqVeZxe+r/HsahIaPumIfyu3AqKogtmac9cNlx/c= Status: R X-Status: X-Keywords: X-UID: 7242 Hello Jura, >> 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? > > I'd say, 'yes' to the first (that would be closest to what is done in > pgfkeys), and given that, 'intersection' to the second. I've been looking at this in more detail, and I suspect that sticking to the 'no nesting' position is easiest (other than \keys_set:nn within \keys_set_... respects the outer position: needed for .meta:n, etc.). I don't see a lot a real use cases for nesting, while I do see quite a bit of complexity in allowing it! >> - Do unknown keys raise an error, or are they ignored as they >> are not in any group? > > Following pgfkeys again, I think they should raise an error. See below. >> - Do unused options need to be collected/available? > > I've not had the occasion to use this myself, but pgfkeys does provide > it. One application that immediately pops to my mind is the control of > key-setting order when the order is important, which is potentially > rather useful. So why not have \keys_set_grouped:nnnN, allowing > something like: OK, I can build in the ability to do this. Worth bearing in mind that grouping is intended for the case where you want to have a 'second axis' for keys. If you always want to be able to set stuff in an order, then \keys_set_known:nnN plus subtrees already works. (We added this a while ago, primarily as Will needed it for fontspec.) > \cs_new_protected:Npn \__mymodule_keys_set_in_order_and_do_something:n #1 > Another question is what should happen to keys that haven't been > assigned a group. Right now, they're filtered out, but perhaps it > would be better to set them. In that way, if there are keys that > should never be filtered, they won't need to be assigned a fallback > group to accomplish this. Pgfkeys provides both options, but it seems > to me it's easier for package writers using l3keys to just follow the > principle that they should assign a key to a group only if they ever > want to filter it out. This ties in with one aspect of how the draft > \keys_set_groups:nnn behaves that I feel should be definitely changed. > Right now, when the second argument is empty, all the keys get set, > which is the opposite of what one would expect. I think, instead, no > keys should be set, except for those that have no group assigned to > them. I believe changing \tl_set:Nx \l__keys_groups_clist {#4} to > \tl_set:Nx \l__keys_groups_clist { , #4 } in the definition of > \__keys_set_grouped:nnnnn would do this. I get the feeling there are two related but distinct requirements here: - Set only keys from specified groups ('opt-in') - Set keys unless they are in groups specified to be filtered out ('opt-out') The following implements that, but note that you will need the 'burning edge' expl3 from GitHub/SVN as I've made some adjustments to the l3keys code to allow for things we certainly will want whatever the final form of groups/families. \cs_new_protected:Npn \__keys_groups_set:n #1 { \prop_if_exist:cT { \c__keys_info_root_tl \l_keys_path_tl } { \prop_put:cnn { \c__keys_info_root_tl \l_keys_path_tl } { groups } {#1} } } \cs_new_protected:cpn { \c__keys_props_root_tl .groups:n } #1 { \__keys_groups_set:n {#1} } \bool_new:N \l__keys_filter_bool \bool_new:N \l__keys_groups_bool \seq_new:N \l__keys_groups_seq \tl_new:N \l__keys_groups_tl \bool_new:N \l__keys_tmp_bool \cs_new_protected:Npn \keys_set_filter:nnn #1#2#3 { \bool_set_true:N \l__keys_filter_bool \seq_set_from_clist:Nn \l__keys_groups_seq {#2} \keys_set:nn {#1} {#3} \bool_set_false:N \l__keys_filter_bool } \cs_new_protected:Npn \keys_set_filter:nnnN #1#2#3#4 { \clist_clear:N \l__keys_unused_clist \keys_set_filter:nn {#1} {#2} {#3} \tl_set:Nx #3 { \exp_not:o { \l__keys_unused_clist } } } \cs_new_protected:Npn \keys_set_groups:nnn #1#2#3 { \bool_set_true:N \l__keys_groups_bool \seq_set_from_clist:Nn \l__keys_groups_seq {#2} \keys_set:nn {#1} {#3} \bool_set_false:N \l__keys_groups_bool } \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} \bool_if:nTF { \l__keys_filter_bool || \l__keys_groups_bool } { \__keys_set_elt_grouped: } { \__keys_set_elt_aux: } } \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: { \prop_if_exist:cTF { \c__keys_info_root_tl \l_keys_path_tl } { \prop_get:cnNTF { \c__keys_info_root_tl \l_keys_path_tl } { groups } \l__keys_groups_tl { \__keys_check_groups: } { \bool_if:NTF \l__keys_filter_bool { \__keys_set_elt_aux: } { \__keys_store_unused: } } } { \bool_if:NTF \l__keys_filter_bool { \__keys_set_elt_aux: } { \__keys_store_unused: } } } \cs_new_protected_nopar:Npn \__keys_store_unused: { \clist_put_right:Nx \l__keys_unknown_clist { \exp_not:o \l_keys_key_tl \bool_if:NF \l__keys_no_value_bool { = { \exp_not:o \l_keys_value_tl } } } } \cs_new_protected_nopar:Npn \__keys_check_groups: { \bool_set_false:N \l__keys_tmp_bool \seq_map_inline:Nn \l__keys_groups_seq { \clist_map_inline:Vn \l__keys_groups_tl { \str_if_eq:nnT {##1} {####1} { \bool_set_true:N \l__keys_tmp_bool \clist_map_break:n { \seq_map_break: } } } } \bool_if:NTF \l__keys_tmp_bool { \bool_if:NTF \l__keys_filter_bool { \__keys_store_unused: } { \__keys_set_elt_aux: } } { \bool_if:NTF \l__keys_filter_bool { \__keys_set_elt_aux: } { \__keys_store_unused: } } } \cs_generate_variant:Nn \clist_map_inline:nn { V } \keys_define:nn { module } { key-one .code:n = { \tl_show:n { key-one } }, key-one .groups:n = { a , b }, key-two .code:n = { \tl_show:n { SAW:~key-two } }, key-two .groups:n = { c , f }, } \keys_set_groups:nnn { module } { a , c } { key-one = value , key-two = value-test , key-odd = value } -- Joseph Wright