% ---------------------------------------------------------------------------- % the XSIM package - tags module % % eXercise Sheets IMproved % % ---------------------------------------------------------------------------- % Clemens Niederberger % Web: https://github.com/cgnieder/xsim % E-Mail: contact@mychemistry.eu % ---------------------------------------------------------------------------- % Copyright 2017--2020 Clemens Niederberger % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % and version 1.3 or later is part of all distributions of LaTeX % version 2005/12/01 or later. % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Clemens Niederberger. % ---------------------------------------------------------------------------- % If you have any ideas, questions, suggestions or bugs to report, please % feel free to contact me. % ---------------------------------------------------------------------------- \XSIMmodule{tags}{tagging of exercises} \xsim_load_modules:n {properties} \seq_new:N \l__xsim_tag_types_seq \bool_new:N \l____xsim_tagged_bool \cs_new_protected:Npn \xsim_set_seq_from_clist:Nn #1#2 { \seq_clear:N #1 \clist_map_inline:nn {#2} { \tl_if_blank:nF {##1} { \seq_put_right:Nn #1 {##1} } } } \cs_generate_variant:Nn \xsim_set_seq_from_clist:Nn {c,Nx} \msg_new:nnn {xsim} {tag-exists} { The~ tag~ type~ `#1'~ already~ exists.~ I~ am~ doing~ nothing. } % #1: name \cs_new_protected:Npn \xsim_new_tag_type:n #1 { \xsim_verbose:n { Declaring~ new~ tag~ type~ `#1'. } \seq_put_right:Nn \l__xsim_tag_types_seq {#1} \seq_remove_duplicates:N \l__xsim_tag_types_seq \seq_new:c {l__xsim_chosen_tags_#1_seq} \bool_new:c {l__xsim_ignore_untagged_#1_bool} \bool_new:c {l____xsim_tagged_#1_bool} \keys_define:nn {xsim} { #1/ignore-untagged .bool_set:c = {l__xsim_ignore_untagged_#1_bool} , #1/ignore-untagged .initial:n = true , #1 .code:n = \xsim_set_seq_from_clist:cn {l__xsim_chosen_tags_#1_seq} {##1} } \prg_new_protected_conditional:cpnn {xsim_if_#1_value:n} ##1 {T,F,TF} { \seq_if_in:cnTF {l__xsim_chosen_tags_#1_seq} {##1} { \prg_return_true: } { \prg_return_false: } } \xsim_declare_property:nnnn { \c_false_bool } { \c_false_bool } { \c_false_bool } {#1} \xsim_declare_printsolutions_condition:nn {#1} { \__xsim_printsolutions_if_tagged:nnnnTF {#1} } \keys_define:nn {xsim/print-solutions} { #1 .choice: , #1/false .code:n = \__xsim_printsolutions_condition:nn {#1} {false} , #1/true .code:n = \__xsim_printsolutions_condition:nn {#1} {true} , #1/unknown .code:n = \keys_set:nn {xsim} { #1 = ##1 } \__xsim_printsolutions_condition:nn {#1} {true} , #1 .initial:n = false } } % #1: tag type \prg_new_protected_conditional:Npnn \xsim_if_tag_type_exist:n #1 {T,F,TF} { \seq_if_in:NnTF \l__xsim_tag_types_seq {#1} { \prg_return_true: } { \prg_return_false: } } % #1: tag type % #2: exercise type % #3: id % #4: print|use \prg_new_protected_conditional:Npnn \__xsim_printsolutions_if_tagged:nnnn #1#2#3#4 {T,F,TF} { \xsim_if_in_list:nnTF {#4} {#2-#3=={true}} { \__xsim_printsolutions_if_condition:nTF {#1} { \__xsim_printsolutions_condition_true: \xsim_if_tagged:nnnTF {#2} {#3} {#1} { \prg_return_true: } { \prg_return_false: } } { \prg_return_false: } } { \prg_return_false: } } % #1: exercise type % #2: id % #3: tag type \prg_new_protected_conditional:Npnn \xsim_if_tagged:nnn #1#2#3 {T,F,TF} { \bool_set_false:c {l____xsim_tagged_#3_bool} \seq_if_empty:cTF {l__xsim_chosen_tags_#3_seq} { \bool_set_true:c {l____xsim_tagged_#3_bool} } { \xsim_set_seq_from_clist:Nx \l__xsim_tmpa_seq { \xsim_get_property:nnn {#1} {#2} {#3} } \seq_if_empty:NTF \l__xsim_tmpa_seq { \bool_set_eq:cc {l____xsim_tagged_#3_bool} {l__xsim_ignore_untagged_#3_bool} } { \seq_map_inline:Nn \l__xsim_tmpa_seq { \seq_if_in:cnT {l__xsim_chosen_tags_#3_seq} {##1} { \bool_set_true:c {l____xsim_tagged_#3_bool} \seq_map_break: } } } } \bool_if:cTF {l____xsim_tagged_#3_bool} { \prg_return_true: } { \prg_return_false: } } % #1: exercise type % #2: id \prg_new_protected_conditional:Npnn \xsim_if_tagged:nn #1#2 {T,F,TF} { \bool_set_true:N \l____xsim_tagged_bool \seq_map_inline:Nn \l__xsim_tag_types_seq { \xsim_if_tagged:nnnF {#1} {#2} {##1} { \bool_set_false:N \l____xsim_tagged_bool \seq_map_break: } } \bool_if:NTF \l____xsim_tagged_bool { \prg_return_true: } { \prg_return_false: } } % #1: exercise type % #2: id % #3: tag type % #4: code \cs_new_protected:Npn \xsim_foreach_exercise_tag:nnnn #1#2#3#4 { \xsim_set_seq_from_clist:Nx \l__xsim_tmpa_seq { \xsim_get_property:nnn {#1} {#2} {#3} } \seq_map_inline:Nn \l__xsim_tmpa_seq {#4} } \cs_generate_variant:Nn \xsim_foreach_exercise_tag:nnnn {oo} % #1: exercise type % #2: id % #3: tag type % #4: sep \cs_new_protected:Npn \xsim_exercise_tags_use:nnnn #1#2#3#4 { \xsim_set_seq_from_clist:Nx \l__xsim_tmpa_seq { \xsim_get_property:nnn {#1} {#2} {#3} } \seq_use:Nn \l__xsim_tmpa_seq {#4} } \cs_generate_variant:Nn \xsim_exercise_tags_use:nnnn {oo} % #1: exercise type % #2: id % #3: tag type % #4: sep between two % #5: sep between more than two % #6: sep between last two \cs_new_protected:Npn \xsim_exercise_tags_use:nnnnnn #1#2#3#4#5#6 { \xsim_set_seq_from_clist:Nx \l__xsim_tmpa_seq { \xsim_get_property:nnn {#1} {#2} {#3} } \seq_use:Nnnn \l__xsim_tmpa_seq {#4} {#5} {#6} } \cs_generate_variant:Nn \xsim_exercise_tags_use:nnnn {oo} \cs_generate_variant:Nn \xsim_exercise_tags_use:nnnnnn {oo} % ---------------------------------------------------------------------------- \file_input_stop: