- Add \ColorText macro to set text color in dark or normal mode. - Merge \HiperRef into \HiRef. - Add macros for checkbox and ballot x to replace those from amssymb.
308 lines
7.9 KiB
TeX
308 lines
7.9 KiB
TeX
\NeedsTeXFormat{LaTeX2e}
|
|
\ProvidesExplPackage{PrimeTeX/packages/CrossRef}{2025-09-16}{1.0}{
|
|
Custom label and reference commands.
|
|
}
|
|
%<@@=CrossRef>
|
|
|
|
\debug_on:n {all}
|
|
|
|
\prop_const_from_keyval:Nn \c_@@_section_names_prop {
|
|
1 = Part,
|
|
2 = Chapter,
|
|
3 = Section,
|
|
4 = Subsection,
|
|
5 = Sub-subsection,
|
|
6 = Paragraph,
|
|
7 = Subparagraph,
|
|
8 = Appendix,
|
|
}
|
|
|
|
\prop_const_from_keyval:Nn \c_@@_section_levels_prop {
|
|
part = 0,
|
|
chapter = 1,
|
|
section = 2,
|
|
subsection = 3,
|
|
subsubsection = 4,
|
|
paragraph = 5,
|
|
subparagraph = 6,
|
|
}
|
|
|
|
\str_const:Nn \c_@@_label_delimiter_str {/}
|
|
\str_const:Nn \c_@@_label_parent_str {.}
|
|
\str_const:Nn \c_@@_label_placeholder_str {*}
|
|
\str_const:Nn \c_@@_appendices_label_str {appendices}
|
|
|
|
\seq_new:N \g_@@_label_seq
|
|
\seq_gclear:N \g_@@_label_seq
|
|
|
|
\NewDocumentCommand{\Part}{s t^ m >{\TrimSpaces}m}{
|
|
\@@_heading:nnnnn {part} {#1} {#2} {#3} {#4}
|
|
\RenewDocumentCommand{\parttitle}{}{#3}
|
|
}
|
|
|
|
\NewDocumentCommand{\Chapter}{s t^ m >{\TrimSpaces}m}{
|
|
\@@_heading:nnnnn {chapter} {#1} {#2} {#3} {#4}
|
|
}
|
|
|
|
\NewDocumentCommand{\Section}{s t^ m >{\TrimSpaces}m}{
|
|
\@@_heading:nnnnn {section} {#1} {#2} {#3} {#4}
|
|
}
|
|
|
|
\NewDocumentCommand{\Subsection}{s t^ m >{\TrimSpaces}m}{
|
|
\@@_heading:nnnnn {subsection} {#1} {#2} {#3} {#4}
|
|
}
|
|
|
|
\NewDocumentCommand{\Subsubsection}{s t^ m >{\TrimSpaces}m}{
|
|
\@@_heading:nnnnn {subsubsection} {#1} {#2} {#3} {#4}
|
|
}
|
|
|
|
\NewDocumentCommand{\Paragraph}{s t^ m >{\TrimSpaces}m}{
|
|
\@@_heading:nnnnn {paragraph} {#1} {#2} {#3} {#4}
|
|
}
|
|
|
|
\NewDocumentCommand{\Subparagraph}{s t^ m >{\TrimSpaces}m}{
|
|
\@@_heading:nnnnn {subparagraph} {#1} {#2} {#3} {#4}
|
|
}
|
|
|
|
\NewDocumentCommand{\Appendices}{}{
|
|
\@@_heading:nnnnn {part} {\c_true_bool} {\c_false_bool} {Appendices} {
|
|
\c_@@_appendices_label_str
|
|
}
|
|
}
|
|
|
|
\NewDocumentCommand{\GetCurrentLabel}{}{
|
|
\seq_use:Nn \g_@@_label_seq {\c_@@_label_delimiter_str}
|
|
}
|
|
|
|
\NewDocumentCommand{\SetCurrentLabel}{
|
|
% #1: Delimiter
|
|
O{\c_@@_label_delimiter_str}
|
|
% #2: Label string.
|
|
>{\TrimSpaces}m
|
|
}{
|
|
\seq_set_split:Nnn \g_@@_label_seq {#1} {#2}
|
|
}
|
|
|
|
\str_new:N \l_@@_esc_parent_str
|
|
\exp_args:Nnne \str_concat:NNN \l_@@_esc_parent_str \c_backslash_str \c_@@_label_parent_str
|
|
|
|
\str_new:N \l_@@_esc_placeholder_str
|
|
\exp_args:Nnne \str_concat:NNN \l_@@_esc_placeholder_str \c_backslash_str \c_@@_label_placeholder_str
|
|
|
|
% MATCH delimiter, parent, and placeholder symbols, but CAPTURE only
|
|
% parents and placeholders, NOT delimiters.
|
|
\exp_args:Nne \regex_const:Nn \c_@@_ref_regex {\c_@@_label_delimiter_str|(\l_@@_esc_parent_str|\l_@@_esc_placeholder_str)}
|
|
\regex_log:N \c_@@_ref_regex
|
|
|
|
\seq_new:N \l_@@_label_seq
|
|
\seq_new:N \l_@@_ref_seq
|
|
|
|
\str_new:N \l_@@_ref_str
|
|
\str_new:N \l_@@_section_name_str
|
|
|
|
\keys_define:nn {HiRef} {
|
|
page .bool_set:N = \l_@@_page_bool,
|
|
}
|
|
|
|
\NewDocumentCommand{\HiRef}{
|
|
% #1: Star (No star = include section name in reference, star = do not include).
|
|
s
|
|
% #2: Key-value arguments.
|
|
O{}
|
|
% #3: Label Reference.
|
|
>{\TrimSpaces}m
|
|
% #4: Link text.
|
|
O{}
|
|
}{ \group_begin:
|
|
\keys_set:nn {HiRef} {#2}
|
|
|
|
%\prop_show:N \c_@@_section_names_prop
|
|
|
|
%\str_set:Ne \l_@@_ref_str {#2}
|
|
|
|
\@@_HiRef_process:Nn \l_@@_ref_str {#3}
|
|
|
|
\str_set:Nn \l_@@_section_name_str {}
|
|
|
|
% Create a reference with the string we just created.
|
|
\hyperref [\l_@@_ref_str] {
|
|
\str_if_empty:nTF {#4} {
|
|
\bool_if:NTF \l_@@_page_bool {
|
|
\bool_if:nF {#1} {Page}~\pageref* {\l_@@_ref_str}
|
|
} {
|
|
% Output the section name only if no star is passed.
|
|
\bool_if:nF {#1} {
|
|
\str_if_eq:eeTF {
|
|
\seq_item:Nn \l_@@_ref_seq {1}
|
|
} {
|
|
\c_@@_appendices_label_str
|
|
} {
|
|
% If the part label is "appendices", the section name is "Appendix".
|
|
\str_set:Ne \l_@@_section_name_str {
|
|
\prop_item:Nn \c_@@_section_names_prop {8}
|
|
}
|
|
} {
|
|
% Otherwise, look up the correct section name.
|
|
\str_set:Ne \l_@@_section_name_str {
|
|
\prop_item:Ne \c_@@_section_names_prop {
|
|
\int_eval:n{\seq_count:N \l_@@_ref_seq}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
\str_if_empty:NF \l_@@_section_name_str {
|
|
\l_@@_section_name_str \nobreakspace
|
|
}
|
|
\ref* {\l_@@_ref_str}
|
|
}
|
|
} {
|
|
#4
|
|
}
|
|
}
|
|
|
|
|
|
\group_end: }
|
|
|
|
% Deprecated in favor of \HiRef{label}[text]
|
|
% \NewDocumentCommand{\HiperRef}{
|
|
% % #1: Label reference.
|
|
% >{\TrimSpaces}m
|
|
% % #2: Display text.
|
|
% m
|
|
% }{ \group_begin:
|
|
|
|
% %\str_set:Ne \l_@@_ref_str {#1}
|
|
|
|
% \@@_HiRef_process:Nn \l_@@_ref_str {#1}
|
|
|
|
% \hyperref[\l_@@_ref_str]{#2}
|
|
|
|
% \group_end: }
|
|
|
|
\cs_new:Nn \@@_HiRef_process:Nn {
|
|
% Split the string on the delimiters.
|
|
\exp_args:NNNe \seq_set_regex_split:NNn \l_@@_ref_seq \c_@@_ref_regex {#2}
|
|
|
|
% The regex split creates a lot of empty items, so remove them.
|
|
\seq_remove_all:Nn \l_@@_ref_seq {}
|
|
|
|
% Log the input and output of the split process for debugging.
|
|
\str_log:n {#2}
|
|
\seq_log:N \l_@@_ref_seq
|
|
|
|
% Copy the current label sequence to a local variable.
|
|
\seq_set_eq:NN \l_@@_label_seq \g_@@_label_seq
|
|
|
|
\seq_log:N \l_@@_label_seq
|
|
|
|
% Iterate through the reference sequence, removing one element from the
|
|
% end of the temporary label sequence for each parent symbol.
|
|
\seq_map_indexed_function:NN \l_@@_ref_seq \@@_seq_map:nn
|
|
|
|
\str_set:Ne \l_@@_ref_head_str {\str_head:n {#2}}
|
|
|
|
\str_log:N \l_@@_ref_head_str
|
|
|
|
% If the reference is relative (i.e. does not start with / or *), add the
|
|
% shortened temporary label sequence to the beginning of the reference
|
|
% sequence.
|
|
\exp_args:Ne \bool_if:nF {
|
|
\str_if_eq_p:NN \l_@@_ref_head_str \c_@@_label_delimiter_str
|
|
|| \str_if_eq_p:NN \l_@@_ref_head_str \c_@@_label_placeholder_str
|
|
} {
|
|
\seq_concat:NNN \l_@@_ref_seq \l_@@_label_seq \l_@@_ref_seq
|
|
}
|
|
|
|
\seq_log:N \l_@@_ref_seq
|
|
|
|
% Join the reference sequence back into a delimited string.
|
|
\str_set:Ne \l_@@_ref_str {
|
|
\seq_use:Ne \l_@@_ref_seq {\c_@@_label_delimiter_str}
|
|
}
|
|
|
|
\str_if_eq:eeF {\str_head:N \l_@@_ref_str} {\c_@@_label_delimiter_str} {
|
|
\str_put_left:Ne \l_@@_ref_str {\c_@@_label_delimiter_str}
|
|
}
|
|
|
|
\str_set_eq:NN #1 \l_@@_ref_str
|
|
}
|
|
|
|
\tl_new:N \l_@@_trash_tl
|
|
|
|
\cs_new:Nn \@@_seq_map:nn {
|
|
\str_case_e:nn {#2} {
|
|
{\c_@@_label_parent_str} {
|
|
\seq_pop_right:NN \l_@@_label_seq \l_@@_trash_tl
|
|
\seq_pop_left:NN \l_@@_ref_seq \l_@@_trash_tl
|
|
}
|
|
{\c_@@_label_placeholder_str} {
|
|
%\message{wildcard~map}
|
|
\seq_pop_left:NN \l_@@_label_seq \l_tmpa_tl
|
|
% \seq_pop_left:NN \l_@@_ref_seq \l_@@_trash_tl
|
|
% \seq_put_left:NN \l_@@_ref_seq \l_tmpa_tl
|
|
\exp_args:NNne \seq_set_item:Nnn \l_@@_ref_seq {#1} {\l_tmpa_tl}
|
|
}
|
|
}
|
|
}
|
|
|
|
\int_new:N \l_@@_current_level_int
|
|
\int_new:N \l_@@_pop_count_int
|
|
\int_new:N \l_@@_pop_index_int
|
|
|
|
\str_new:N \l_@@_label_str
|
|
|
|
\cs_new:Nn \@@_heading:nnnnn { \group_begin:
|
|
% #1: Section name: part, chapter, section, etc.
|
|
% #2: Star (passed to default sectioning command)
|
|
% #3: ^ token: suppresses sectioning command.
|
|
% #4: Section title
|
|
% #5: Label
|
|
|
|
\debug_on:n {all}
|
|
|
|
% Get the numeric level of the section command.
|
|
\prop_get:NnN \c_@@_section_levels_prop {#1} \l_@@_current_level_int
|
|
|
|
% \message{^^J@@_heading:~#5~\seq_use:Ne \g_@@_label_seq {\c_@@_label_delimiter_str}}
|
|
|
|
\seq_set_eq:NN \l_@@_label_seq \g_@@_label_seq
|
|
|
|
\int_set:Nn \l_@@_pop_count_int {
|
|
\seq_count:N \l_@@_label_seq - \l_@@_current_level_int
|
|
}
|
|
|
|
\int_while_do:nNnn {\l_@@_pop_index_int} < {\l_@@_pop_count_int} {
|
|
\seq_if_empty:NF \l_@@_label_seq {
|
|
\seq_pop_right:NN \l_@@_label_seq \l_tmpa_tl
|
|
}
|
|
\int_incr:N \l_@@_pop_index_int
|
|
}
|
|
|
|
% Add the new label to the end of the modified label sequence.
|
|
\seq_put_right:Ne \l_@@_label_seq {#5}
|
|
|
|
\seq_gset_eq:NN \g_@@_label_seq \l_@@_label_seq
|
|
|
|
% Join the label sequence into a string.
|
|
\str_set:Ne \l_@@_label_str {
|
|
\seq_use:Ne \l_@@_label_seq {\c_@@_label_delimiter_str}
|
|
}
|
|
|
|
% Add a delimiter to the beginning of the label string to indicate this is
|
|
% an absolute reference.
|
|
\str_put_left:Ne \l_@@_label_str {\c_@@_label_delimiter_str}
|
|
|
|
% If the caret argument is NOT present, output the heading.
|
|
\bool_if:nF {#3} {
|
|
% Pass along the star argument if it is present.
|
|
\bool_if:nTF {#2} {
|
|
\use:c {#1} * {#4}
|
|
} {
|
|
\use:c {#1} {#4}
|
|
}
|
|
}
|
|
% Output the label.
|
|
\exp_args:Ne \label {\l_@@_label_str}
|
|
\group_end: }
|
|
|
|
\debug_off:n {all} |