diff options
Diffstat (limited to 'macros/latex/contrib/genealogy-profiles/latex/genealogy-profiles.sty')
-rw-r--r-- | macros/latex/contrib/genealogy-profiles/latex/genealogy-profiles.sty | 848 |
1 files changed, 848 insertions, 0 deletions
diff --git a/macros/latex/contrib/genealogy-profiles/latex/genealogy-profiles.sty b/macros/latex/contrib/genealogy-profiles/latex/genealogy-profiles.sty new file mode 100644 index 0000000000..69f1cf00d7 --- /dev/null +++ b/macros/latex/contrib/genealogy-profiles/latex/genealogy-profiles.sty @@ -0,0 +1,848 @@ +\RequirePackage{expl3}[2023-10-10] +\ProvidesExplPackage{genealogy-profiles}{2024/01/24}{0.1}{Macros for creating genealogical profiles} + +% License: CC-BY-SA 4.0 +% Author: Mikkel Eide Eriksen <mikkel.eriksen@gmail.com> + +\RequirePackage{genealogytree} +\RequirePackage{hyperref} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Key setup +% + +\keys_define:nn { genealogy-profiles } +{ + name~part~order .code:n = { + \seq_gset_from_clist:Nn \g__gpr_name_part_order_seq {#1} + } , + name~type .choices:nn = { + given~and~surname , + nordic~historical , + } { + \int_case:nn { \l_keys_choice_int } { + {1} { + \seq_gset_from_clist:Nn \g__gpr_name_part_order_seq + { givenname, surname } + } + {2} { + \seq_gset_from_clist:Nn \g__gpr_name_part_order_seq + { givenname, patronymic, byname } + } + } + + + } , + + auto~id .bool_set:N = \l__gpr_autoid_bool , + auto~id .default:n = { true } , + auto~id~prefix .tl_set:N = \l__gpr_id_prefix_tl , + + % formatting profiles + begin~profile .tl_set:N = \l__gpr_begin_profile_tl , + end~profile .tl_set:N = \l__gpr_end_profile_tl , + begin~header .tl_set:N = \l__gpr_begin_header_tl , + end~header .tl_set:N = \l__gpr_end_header_tl , + begin~life~events .tl_set:N = \l__gpr_begin_life_events_tl , + end~life~events .tl_set:N = \l__gpr_end_life_events_tl , + + reference~style .cs_set:Np = \gpr__reference_style_handler:nnn #1#2#3 , + unknown~reference~style .cs_set:Np = \gpr__unknown_reference_handler:nn #1#2 , + page~number~style .cs_set:Np = \gpr__page_number_handler:n #1 , + + % name part styling + givenname~style .tl_set:N = \l__gpr_givenname_style_tl , + patronymic~style .tl_set:N = \l__gpr_patronymic_style_tl , + surname~style .tl_set:N = \l__gpr_surname_style_tl , + byname~style .tl_set:N = \l__gpr_byname_style_tl , + + header~format .tl_set:N = \l__gpr_header_format_tl , + auto~header .bool_set:N = \l__gpr_auto_header_bool , + + % indexes + id~index .tl_set:N = \l__gpr_id_index_tl , + fullname~index .tl_set:N = \l__gpr_fullname_index_tl , + patronymic~index .tl_set:N = \l__gpr_patronymic_index_tl , + surname~index .tl_set:N = \l__gpr_surname_index_tl , + byname~index .tl_set:N = \l__gpr_byname_index_tl , + + nest~index~entries .bool_set:N = \l__gpr_nest_index_entries_bool , + id~in~index~entries .bool_set:N = \l__gpr_id_in_index_entries_bool , + main~index~entry~style .tl_set:N = \l__gpr_main_index_entry_style_tl , + include~unknown~in~index .bool_set:N = \l__gpr_include_unknown_in_index_bool , + include~unknown~in~index .default:n = { true } , + include~ambiguous~in~index .bool_set:N = \l__gpr_include_ambiguous_in_index_bool , + include~ambiguous~in~index .default:n = { true } , + + debug~log .bool_set:N = \l__gpr_debug_log_bool +} + +\keys_define:nn { genealogy-profiles / profile } +{ + id .tl_set:N = \l__gpr_id_tl , + fullname .tl_set:N = \l__gpr_fullname_tl , + givenname .tl_set:N = \l__gpr_givenname_tl , + patronymic .tl_set:N = \l__gpr_patronymic_tl , + surname .tl_set:N = \l__gpr_surname_tl , + byname .tl_set:N = \l__gpr_byname_tl , + + life~events .tl_set:N = \l__gpr_life_events_tl , + + no~index .bool_set:N = \l__gpr_no_index_bool , +} + +\NewDocumentCommand { \gprKeys } { +m } { + \keys_set:nn { genealogy-profiles } { #1 } +} + +% set some defaults +\keys_set:nn { genealogy-profiles } { + auto~id , + include~unknown~in~index , + include~ambiguous~in~index , + name~type = { given~and~surname } , + header~format = { \gprStyledName \hfill \gprID } , + reference~style = { + #1 \gpr_super_subscript:nn {#2} {#3} + } , + page~number~style = { + p.\nobreakspace#1 + } , + unknown~reference~style = { + \color_select:n {red} + #1 + \tl_if_novalue:nF {#2} { ~ (#2) } + } , +} + +\cs_generate_variant:Nn \gpr__unknown_reference_handler:nn { + Vn, nV +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Errors and warnings +% + +\msg_new:nnn +{ genealogy-profiles } { reference-recorded } +{ Reference ~ recorded ~ from ~ #1 ~ to ~ #2 ~ on ~ input ~ line ~ #3 } + +\msg_new:nnn +{ genealogy-profiles } { ambiguous-reference } +{ Ambiguous ~ reference: ~ #1 ~ on ~ input ~ line ~ #2, ~ + use ~ IDs ~ to ~ fix ~ references } + +\msg_new:nnn +{ genealogy-profiles } { unknown-reference-id } +{ Reference ~ to ~ unknown ~ id: ~ #1 ~ on ~ input ~ line ~ #2 } + +\msg_new:nnn +{ genealogy-profiles } { unknown-reference-name } +{ Reference ~ to ~ unknown ~ name: ~ #1 ~ on ~ input ~ line ~ #2 } + +\msg_new:nnn +{ genealogy-profiles } { missing-backref } +{ Missing ~ backreference: ~ #1 ~ refers ~ to ~ #2 ~ but ~ not ~ vice ~ versa ~ + on ~ input ~ line ~ #3 } + +\msg_new:nnnn +{ genealogy-profiles } { missing-id } +{ You ~ have ~ not ~ assigned ~ an ~ ID ~ to ~ profile: ~ #1 ~ on ~ input ~ line ~ #2 } +{ You ~ must ~ either ~ give ~ each ~ profile ~ a ~ unique ~ ID, ~ + or ~ let ~ them ~ be ~ autogenerated. } + +\msg_new:nnnn +{ genealogy-profiles } { reused-id } +{ You ~ have ~ assigned ~ an ~ ID ~ that ~ is ~ already ~ in ~ use: ~ #1 ~ + on ~ input ~ line ~ #2 } +{ You ~ must ~ either ~ give ~ every ~ profile ~ a ~ unique ~ ID, ~ + or ~ let ~ them ~ be ~ autogenerated. } + +\msg_new:nnn +{ genealogy-profiles } { ambiguous-rawname } +{ Multiple ~ profiles ~ with ~ the ~ name ~ '#1', ~ + you ~ will ~ need ~ to ~ use ~ IDs ~ to ~ reference ~ them } + +\cs_new_protected:Nn \gpr_warning:nn +{ + \msg_warning:nnee { genealogy-profiles } { #1 } { #2 } { \the\inputlineno } +} + +\cs_new_protected:Nn \gpr_warning:nnn +{ + \msg_warning:nneee { genealogy-profiles } { #1 } { #2 } { #3 } { \the\inputlineno } +} + +\cs_new_protected:Nn \gpr_error:nn +{ + \msg_error:nnee { genealogy-profiles } { #1 } { #2 } { \the\inputlineno } +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Extensions to expl3 library +% + +\prg_generate_conditional_variant:Nnn \tl_if_blank:n + { v, V } { F } + +\prg_generate_conditional_variant:Nnn \property_if_recorded:nn + { en } { T, TF } + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Properties +% + +\seq_clear_new:N \l__gpr_floruit_years_seq +\property_new:nnnn { floruit-years } { now } { \c_novalue_tl } { + \seq_use:Nn \l__gpr_floruit_years_seq {,} +} + +\tl_clear_new:N \l__gpr_fullname_raw_tl +\property_new:nnnn { raw-name } { now } { \c_novalue_tl } { + \tl_use:N \l__gpr_fullname_raw_tl +} + +\prop_clear_new:N \g__gpr_name_to_id_prop % saved at end, loaded into _active at start +\prop_clear_new:N \g__gpr_name_to_id_active_prop % used for lookups during run +\property_new:nnnn { names-ids } { now } { \c_novalue_tl } { + \prop_to_keyval:N \g__gpr_name_to_id_prop +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Names +% + +\tl_const:Ne \c_gpr_underscore_tl { \char_generate:nn { `_ } { 8 } } + +\cs_new_protected:Nn \gpr_name_handler:n +{ + \tl_set:Nn \l__gpr_fullname_tl {#1} + \tl_replace_all:NVn \l__gpr_fullname_tl \c_gpr_underscore_tl { ~ } + + \seq_set_split:Nnn \l_tmpa_seq {~} {#1} + \seq_map_indexed_inline:Nn \g__gpr_name_part_order_seq { + \tl_set:Ne \l_tmpa_tl { \seq_item:Nn \l_tmpa_seq {##1} } + \tl_replace_all:NVn \l_tmpa_tl \c_gpr_underscore_tl { ~ } + \tl_if_blank:VTF \l_tmpa_tl { + \tl_clear:c { l__gpr_##2_tl } + } { + \tl_set:cV { l__gpr_##2_tl } \l_tmpa_tl + } + } + + \tl_clear_new:N \l__gpr_styled_name_tl + \gpr_style_name:N \l__gpr_styled_name_tl +} +\cs_generate_variant:Nn \gpr_name_handler:n { + V, e +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% IDs +% + +\cs_new_protected:Nn \gpr_map_name_to_id:Nnn +{ + % check if name already has an associated id + \prop_get:NVNTF #1 \l__gpr_fullname_raw_tl \l_tmpb_tl + { + % mark name ambiguous if already reserved + \tl_if_eq:NNF \l__gpr_id_tl \l_tmpb_tl + { + \msg_note:nne { genealogy-profiles } { ambiguous-rawname } + { \tl_use:N \l__gpr_fullname_raw_tl } + \prop_gput:NVn #1 \l__gpr_fullname_raw_tl {_AMBIGUOUS_} + } + } + { + % otherwise save raw name -> id + \prop_gput:NVV #1 \l__gpr_fullname_raw_tl \l__gpr_id_tl + } +} +\cs_generate_variant:Nn \gpr_map_name_to_id:Nnn { + NVV +} + +\seq_clear_new:N \g__gpr_used_profile_ids_seq + +\cs_new_protected:Nn \gpr_generate_unique_id: +{ + \tl_clear_new:N \l_tmpa_tl + + \tl_put_right:NV \l_tmpa_tl \l__gpr_id_prefix_tl + + % build base id from initials + \seq_map_indexed_inline:Nn \g__gpr_name_part_order_seq { + \tl_if_empty:cTF { l__gpr_##2_tl } { + \tl_put_right:Ne \l_tmpa_tl { - } + } { + \tl_put_right:Ne \l_tmpa_tl { \tl_item:cn { l__gpr_##2_tl } {1} } + } + } + + % find unused variant + \int_zero_new:N \l__gpr_id_index_int + \bool_set_false:N \l__gpr_id_found_bool + + \bool_do_until:nn { \l__gpr_id_found_bool } { + \int_incr:N \l__gpr_id_index_int + \tl_set:Ne \l__gpr_id_tl { + \tl_use:N \l_tmpa_tl + \int_use:N \l__gpr_id_index_int + } + \seq_if_in:NVTF \g__gpr_used_profile_ids_seq \l__gpr_id_tl + { + \bool_set_false:N \l__gpr_id_found_bool + } + { + % mark id as used + \seq_gput_right:NV \g__gpr_used_profile_ids_seq \l__gpr_id_tl + + \bool_set_true:N \l__gpr_id_found_bool + } + } +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% References +% + +\prop_new:N \g__gpr_references_prop + +\cs_new_protected:Nn \gpr_save_reference:nn +{ + \prop_if_in:NnTF \g__gpr_references_prop { #1 } { + \prop_get:NnN \g__gpr_references_prop { #1 } \l_tmpa_tl + } { + \tl_clear:N \l_tmpa_tl + } + + % wrap ID as _ID_ so we can match them out later + \tl_put_right:Nn \l_tmpa_tl { _#2_ } + + \prop_gput:NnV \g__gpr_references_prop { #1 } \l_tmpa_tl + +% \msg_note:nneee { genealogy-profiles } { reference-recorded } +% { #1 } { #2 } {\the\inputlineno} +} +\cs_generate_variant:Nn \gpr_save_reference:nn { + Vn +} + +\cs_new_protected:Nn \gpr_check_backrefs:nn +{ + \regex_extract_all:nnN { _([^_]+)_ } {#2} \l_tmpa_seq + \seq_map_inline:Nn \l_tmpa_seq { + % dont test entire matches (_ID_), only submatches (ID) + \tl_if_eq:neF { _ } { \tl_item:nn { ##1 } {1} } + { + \seq_if_in:NnT \g__gpr_used_profile_ids_seq { ##1 } { + \prop_get:NnN \g__gpr_references_prop {##1} \l_tmpa_tl + \regex_match:nVF { #1 } { \l_tmpa_tl } { + \gpr_warning:nnn { missing-backref } { #1 } { ##1 } + } + } + } + } +} + +\cs_new:Nn \gpr_init_names_to_keys:n +{ + \tl_if_novalue:nF {#1} { + \prop_set_from_keyval:Nn \g__gpr_name_to_id_active_prop {#1} + } +} +\cs_generate_variant:Nn \gpr_init_names_to_keys:n { + e +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Hooks +% + +\AddToHook{begindocument/end} +{ + \gpr_init_names_to_keys:e { \property_ref:nn { gpr } { names-ids } } +} + +\AddToHook{shipout/lastpage} +{ + \property_record:ee { gpr } { names-ids } + \prop_map_inline:Nn \g__gpr_references_prop { + \gpr_check_backrefs:nn {##1} {##2} + } +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Indexing +% + +\cs_new:Nn \gpr_add_to_named_index:nnN { + \index[#1]{ + #2 + \bool_if:nT { #3 && !\tl_if_blank_p:V \l__gpr_main_index_entry_style_tl } + { | \tl_use:N \l__gpr_main_index_entry_style_tl } + } +} +\cs_generate_variant:Nn \gpr_add_to_named_index:nnN { + VVN, VeN +} + +\cs_new:Nn \gpr_build_index_entry:Nnnn { + \seq_clear:N \l_tmpa_seq + \clist_map_inline:nn {#2} { + \tl_if_blank:vF { l__gpr_##1_tl } { + \seq_put_right:Nv \l_tmpa_seq { l__gpr_##1_tl } + } + } + + \seq_clear:N \l_tmpb_seq + \clist_map_inline:nn {#3} { + \tl_if_blank:vF { l__gpr_##1_tl } { + \seq_put_right:Nv \l_tmpb_seq { l__gpr_##1_tl } + } + } + + \tl_set:Ne #1 { + \seq_use:Nn \l_tmpa_seq {~} + \bool_if:NTF \l__gpr_nest_index_entries_bool { ! } { ,~ } + \seq_use:Nn \l_tmpb_seq {~} + \bool_if:NT \l__gpr_id_in_index_entries_bool { ~ (#4) } + } +} + +\cs_new:Nn \gpr_add_to_indexes:nN +{ + \tl_if_blank:VF \l__gpr_id_index_tl { + \tl_if_novalue:nF {#1} { + \gpr_add_to_named_index:VeN \l__gpr_id_index_tl + { #1 ~ \tl_use:N \l__gpr_fullname_tl } + #2 + } + } + + \tl_if_blank:VF \l__gpr_fullname_index_tl { + \gpr_add_to_named_index:VVN + \l__gpr_fullname_index_tl + { + \tl_use:N \l__gpr_fullname_tl + \bool_if:NT \l__gpr_id_in_index_entries_bool { ~ (\tl_use:N #1) } + } + #2 + } + + \tl_if_blank:VF \l__gpr_patronymic_index_tl { + \tl_if_blank:VF \l__gpr_patronymic_tl { + \gpr_build_index_entry:Nnnn \l_tmpa_tl + { patronymic, surname, byname } + { givenname } + { #1 } + + \gpr_add_to_named_index:VVN \l__gpr_patronymic_index_tl \l_tmpa_tl #2 + } + } + \tl_if_blank:VF \l__gpr_surname_index_tl { + \tl_if_blank:VF \l__gpr_surname_tl { + \gpr_build_index_entry:Nnnn \l_tmpa_tl + { surname, byname } + { givenname, patronymic } + { #1 } + + \gpr_add_to_named_index:VVN \l__gpr_surname_index_tl \l_tmpa_tl #2 + } + } + \tl_if_blank:VF \l__gpr_byname_index_tl { + \tl_if_blank:VF \l__gpr_byname_tl { + \gpr_build_index_entry:Nnnn \l_tmpa_tl + { byname } + { givenname, patronymic, surname } + { #1 } + + \gpr_add_to_named_index:VVN \l__gpr_byname_index_tl \l_tmpa_tl #2 + } + } +} +\cs_generate_variant:Nn \gpr_add_to_indexes:nN { + VN +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Styling +% + +\cs_new_protected:Nn \gpr_style_name:N +{ + \seq_clear_new:N \l__gpr_styled_name_seq + + \seq_map_inline:Nn \g__gpr_name_part_order_seq { + \tl_if_blank:vF { l__gpr_##1_tl } { + \seq_put_right:Nn \l__gpr_styled_name_seq { + \group_begin: + \tl_use:c { l__gpr_##1_style_tl } + \tl_use:c { l__gpr_##1_tl } + \group_end: + } + } + } + + \tl_set:Nn #1 { \seq_use:Nn \l__gpr_styled_name_seq {~} } +} + +\cs_new_protected:Nn \gpr_format_floruit:N +{ + \int_compare:nNnTF { \seq_count:N \l__gpr_floruit_years_seq } = {1} + { + \tl_set:Ne #1 { floruit- = { \seq_item:Nn \l__gpr_floruit_years_seq {1} } } + } + { + \int_zero_new:N \l__gpr_floruit_from_int + \int_set:Nn \l__gpr_floruit_from_int { 9999 } + \int_zero_new:N \l__gpr_floruit_to_int + \int_set:Nn \l__gpr_floruit_to_int { 0000 } + \seq_map_inline:Nn \l__gpr_floruit_years_seq { + \int_set:Nn \l__gpr_floruit_from_int + { \int_min:nn {##1} { \l__gpr_floruit_from_int } } + \int_set:Nn \l__gpr_floruit_to_int + { \int_max:nn {##1} { \l__gpr_floruit_to_int } } + } + \tl_set:Ne #1 { + floruit- = { + \int_use:N \l__gpr_floruit_from_int / \int_use:N \l__gpr_floruit_to_int + } + } + } +} + +\cs_new_protected:Nn \gpr_super_subscript:nn +{ + \group_begin: + \hbox_set:Nn \l_tmpa_box { \textsuperscript {#1} } + \hbox_set:Nn \l_tmpb_box { \textsubscript {#2} } + \hbox_to_wd:nn + { \dim_max:nn { \box_wd:N \l_tmpa_box } { \box_wd:N \l_tmpb_box } } + { \hbox_overlap_right:n { \box_use:N \l_tmpa_box } \box_use:N \l_tmpb_box } + \group_end: +} + +\cs_new_protected:Nn \gpr_typeset_reference:nnnN +{ + \property_if_recorded:nTF { gpr/#1/target } + { + \hyperlink{ \property_ref:nn { gpr/#1/target } { target } } { + \gpr__reference_style_handler:nnn { + \tl_if_blank:nTF { #3 } { #2 } { + % render styled #3 if present + \group_begin: + \gpr_name_handler:n {#3} + \tl_use:N \l__gpr_styled_name_tl + \group_end: + } + } { + #1 + } { + \gpr__page_number_handler:n { + \property_ref:nnn { gpr/#1/target } { page } { + \gpr__unknown_reference_handler:nV { \bfseries ?? } \c_novalue_tl + } + } + } + } + } + { + \gpr_warning:nn { unknown-reference-id } { #1 } + \gpr__unknown_reference_handler:nn {#2} { unknown~id: ~ #1 } + } + \bool_if:NF #4 { + \gpr_add_to_indexes:nN { #1 } \c_false_bool + } + \gpr_save_reference:Vn \l__gpr_id_tl { #1 } +} +\cs_generate_variant:Nn \gpr_typeset_reference:nnnN { + nVnN, VVnN +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% genealogytree package integration +% + +\cs_new_protected:Nn \gpr_set_genealogytree_keys:n +{ + \gtrset{ database/.cd, #1 } +} +\cs_generate_variant:Nn \gpr_set_genealogytree_keys:n { + V +} + +\prg_new_protected_conditional:Nnn \gpr_if_lifespan_defined: {T,F,TF} +{ + \bool_if:nTF { + ( \cs_if_exist_p:c { gtrDBbirthyear } + || \cs_if_exist_p:c { gtrDBbaptismyear } ) + && + ( \cs_if_exist_p:c { gtrDBdeathyear } + || \cs_if_exist_p:c { gtrDBburialyear } ) + } { + \prg_return_true: + } { + \prg_return_false: + } +} + +\gtrDeclareDatabaseFormat{gtr_db_format}{}{% + \begin{gtrprintlist}{\par}{\unskip,\ }{\unskip.}{\unskip}% + \gtr@list@event{birth}% + \gtr@list@event{baptism}% + \gpr_if_lifespan_defined:F { + \gtr@list@event{floruit} + } + \gtr@list@event{death}% + \gtr@list@event{burial}% + \end{gtrprintlist}% + \gtr@print@infolist% +} +\gtrset{database~format=gtr_db_format} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% User commands +% + +\NewDocumentEnvironment { gprProfile* } { m O{} } { + \bool_if:NT \l__gpr_debug_log_bool { + \tl_log:e {\the\inputlineno} + \tl_log:n {BEGIN ~ #1} + } + \group_begin: + \keys_set:nn { genealogy-profiles / profile } { #1, life~events={#2} } + + \tl_if_empty:NTF \l__gpr_fullname_tl { + % if no full name supplied, build one from given parts + \seq_clear:N \l_tmpa_seq + \seq_map_inline:Nn \g__gpr_name_part_order_seq { + \tl_if_blank:vF { l__gpr_##1_tl } { + \seq_put_right:Nv \l_tmpa_seq { l__gpr_##1_tl } + } + } + \tl_set:Ne \l__gpr_fullname_tl { \seq_use:Nn \l_tmpa_seq {~} } + \tl_set_eq:NN \l__gpr_fullname_raw_tl \l__gpr_fullname_tl + \tl_clear_new:N \l__gpr_styled_name_tl + \gpr_style_name:N \l__gpr_styled_name_tl + } { + % otherwise use full name to split into parts + \tl_set_eq:NN \l__gpr_fullname_raw_tl \l__gpr_fullname_tl + \gpr_name_handler:V \l__gpr_fullname_tl + } + + % ensure unique id + \tl_if_empty:NTF \l__gpr_id_tl { + \bool_if:NTF \l__gpr_autoid_bool { + \gpr_generate_unique_id: + } { + \gpr_error:nn { missing-id } { \l__gpr_fullname_tl } + } + } { + \seq_if_in:NVT \g__gpr_used_profile_ids_seq \l__gpr_id_tl { + \gpr_error:nn { reused-id } { \l__gpr_id_tl } + } + \seq_gput_right:NV \g__gpr_used_profile_ids_seq \l__gpr_id_tl + } + \gpr_map_name_to_id:NVV \g__gpr_name_to_id_prop \l__gpr_fullname_raw_tl \l__gpr_id_tl + \gpr_map_name_to_id:NVV \g__gpr_name_to_id_active_prop \l__gpr_fullname_raw_tl \l__gpr_id_tl + + % store raw name in aux + \property_record:ee { gpr/\tl_use:N \l__gpr_id_tl/name } { raw-name } + + % init floruit years + \property_if_recorded:enT { gpr/\tl_use:N \l__gpr_id_tl/floruit } { floruit-years } { + \tl_set:Ne \l_tmpa_tl { + \property_ref:ee { gpr/\tl_use:N \l__gpr_id_tl/floruit } { floruit-years } + } + \seq_set_split:NnV \l__gpr_floruit_years_seq {,} \l_tmpa_tl + + \tl_clear_new:N \l__formatted_gpr_floruit_tl + \gpr_format_floruit:N \l__formatted_gpr_floruit_tl + \tl_put_right:Ne \l__gpr_life_events_tl { + , + \tl_use:N \l__formatted_gpr_floruit_tl + } + } + \seq_clear_new:N \l__gpr_floruit_years_seq + + % placeholders for id and names + \cs_set:Npe \gprID { \tl_use:N \l__gpr_id_tl } + \cs_set:Npe \gprStyledName { \tl_use:N \l__gpr_styled_name_tl } + \cs_set:Npe \gprFullName { \tl_use:N \l__gpr_fullname_tl } + \cs_set:Npe \gprGivenName { \tl_use:N \l__gpr_givenname_tl } + \cs_set:Npe \gprPatronymic { \tl_use:N \l__gpr_patronymic_tl } + \cs_set:Npe \gprSurname { \tl_use:N \l__gpr_surname_tl } + \cs_set:Npe \gprByname { \tl_use:N \l__gpr_byname_tl } + \cs_set:Npe \gprHeader { \tl_use:N \l__gpr_header_format_tl } + + % set hyperref target just before typesetting + \MakeLinkTarget*{ gpr/\tl_use:N \l__gpr_id_tl/target } + + % begin typesetting + \tl_use:N \l__gpr_begin_profile_tl + + % record properties for id + \property_record:ee { gpr/\tl_use:N \l__gpr_id_tl/target } { page, target } + + % add to indexes unless key set + \bool_if:NF \l__gpr_no_index_bool { + \gpr_add_to_indexes:VN \l__gpr_id_tl \c_true_bool + } + + \bool_if:NT \l__gpr_auto_header_bool { + \tl_use:N \l__gpr_begin_header_tl + \tl_use:N \l__gpr_header_format_tl + \tl_use:N \l__gpr_end_header_tl + } + + % typeset life events + \tl_if_empty:NF \l__gpr_life_events_tl { + \tl_use:N \l__gpr_begin_life_events_tl + + \gpr_set_genealogytree_keys:V \l__gpr_life_events_tl + \gtrPrintDatabase + + \tl_use:N \l__gpr_end_life_events_tl + } +}{ + % end typesetting + \tl_use:N \l__gpr_end_profile_tl + + % save floruit years including updates from \gprYear + \seq_if_empty:NF \l__gpr_floruit_years_seq { + \property_record:ee { gpr/\tl_use:N \l__gpr_id_tl/floruit } { floruit-years } + } + \group_end: + \bool_if:NT \l__gpr_debug_log_bool { + \tl_log:e {\the\inputlineno} + \tl_log:n {END ~ #1} + } +} + +\NewDocumentEnvironment { gprProfile } { O{} m O{} } { + \begin{gprProfile*}{fullname={#2}, #1}[#3] +}{ + \end{gprProfile*} +} + +\cs_new_protected:Nn \gpr_cmd_ref:Nnn +{ + \group_begin: + \tl_if_empty:nTF {#2} + { + % no id provided, so we use the name to try looking it up + \gpr_name_handler:n { #3 } + \prop_get:NnNTF \g__gpr_name_to_id_active_prop {#3} \l_tmpa_tl + { + \str_if_eq:VnTF \l_tmpa_tl {_AMBIGUOUS_} + { + \gpr_warning:nn { ambiguous-reference } { \l__gpr_fullname_tl } + \gpr__unknown_reference_handler:Vn \l__gpr_styled_name_tl + { ambiguous } + \bool_if:NT \l__gpr_include_ambiguous_in_index_bool { + \gpr_add_to_indexes:nN { ambiguous } \c_false_bool + } + } + { + \gpr_typeset_reference:VVnN \l_tmpa_tl \l__gpr_styled_name_tl {} #1 + } + } + { + \gpr_warning:nn { unknown-reference-name } { #3 } + \gpr__unknown_reference_handler:Vn \l__gpr_styled_name_tl { unknown~name } + \bool_if:NT \l__gpr_include_unknown_in_index_bool { + \gpr_add_to_indexes:nN { unknown } \c_false_bool + } + } + } + { + % id provided, find the name to use for indexes + \property_if_recorded:nTF { gpr/#2/name } { + \gpr_name_handler:e { + \property_ref:nn { gpr/#2/name } { raw-name } + } + } { + \gpr_name_handler:n {#3} + } + \gpr_typeset_reference:nVnN {#2} \l__gpr_styled_name_tl {#3} #1 + } + \group_end: +} +\cs_generate_variant:Nn \gpr_cmd_ref:Nnn { + Nee +} +\NewDocumentCommand { \gprRef } { s O{} m } { + \gpr_cmd_ref:Nee #1 {#2} {#3} +} + + +\NewDocumentCommand { \gprName } { s m } { + \group_begin: + \gpr_name_handler:n { #2 } + \tl_use:N \l__gpr_styled_name_tl + \bool_if:nT { !#1 && \l__gpr_include_unknown_in_index_bool } + { + \bool_set_false:N \l__gpr_id_in_index_entries_bool + \gpr_add_to_indexes:nN { unknown } \c_false_bool + } + \group_end: +} + + +\cs_new_protected:Nn \gpr_cmd_year:n +{ + % record floruit year + \seq_if_in:NnF \l__gpr_floruit_years_seq {#1} { + \seq_gput_right:Nn \l__gpr_floruit_years_seq {#1} + } +} +\cs_generate_variant:Nn \gpr_cmd_year:n { + e +} +\NewDocumentCommand { \gprYear } { s m } { + \gpr_cmd_year:e {#2} + \bool_if:NF { #1 } { #2 } +} + + +\cs_new_protected:Nn \gpr_cmd_years:n +{ + % split year range + \seq_set_split:Nnn \l_tmpa_seq { - } {#1} + + % first year + \seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl + \seq_if_in:NVF \l__gpr_floruit_years_seq \l_tmpa_tl { + \seq_gput_right:NV \l__gpr_floruit_years_seq \l_tmpa_tl + } + + % last year + \seq_pop_right:NN \l_tmpa_seq \l_tmpb_tl + \int_set:Nn \l_tmpa_int { \tl_count:N \l_tmpa_tl - \tl_count:N \l_tmpb_tl } + \tl_put_left:Ne \l_tmpb_tl { + \tl_range:Nnn \l_tmpa_tl { 1 } { \l_tmpa_int } + } + \seq_if_in:NVF \l__gpr_floruit_years_seq \l_tmpb_tl { + \seq_gput_right:NV \l__gpr_floruit_years_seq \l_tmpb_tl + } +} +\cs_generate_variant:Nn \gpr_cmd_years:n { + e +} +\NewDocumentCommand { \gprYears } { s m } { + \gpr_cmd_years:e {#2} + \bool_if:NF { #1 } { #2 } +} + + +\NewDocumentCommand { \gprSpouse } { s o m o } { + \gtrsymMarried{} ~ + \IfValueT{#4} { #4 ~ } + \IfBooleanTF {#1} { + \gprRef*[#2]{#3} + } { + \gprRef[#2]{#3} + } +}
\ No newline at end of file |