%!TEX root=template.tex %% ---------------------------------------------------------------------------- %% novathesis — nt-setup.sty %% ---------------------------------------------------------------------------- %% %% Version 8.4.0 (2026-09-27) %% Copyright (C) 2004-26 by João M. Lourenço %% Departamento de Informática (www.di.fct.unl.pt) %% Faculdade de Ciências e Tecnologia (www.fct.unl.pt) %% Universidade NOVA de Lisboa (www.unl.pt) %% %% Setup/initialization: config loading, babel, metadata, printing engine, school logic %% ---------------------------------------------------------------------------- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% LOADING CUSTOMIZATION STUFF - part 1 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % -------------------------------------------------------- % Define DEFAULT corollaryUES for COVER and COPYRIGHT languages % and HYPERLINK color \ntsetup{lang = \option{/novathesis/lang/main}, color/links = DarkBlue, color/glossaries/gls = None, } % \NTRunHook{memoir} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% HOOK DECLARATIONS %% Pre-declare all known novathesis hooks so that \NTAddToHook can be %% used before the hook is first run. Parametric hooks (e.g. cover/#-#) %% are activated dynamically inside \NTRunHook at call time. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \NTDeclareHook{afterloading/schoolconfig} \NTDeclareHook{printcovers/pre} \NTDeclareHook{printcovers/post} \NTDeclareHook{cover/pre} \NTDeclareHook{cover/post} \NTDeclareHook{cover/text/pre} \NTDeclareHook{cover/text/post} % Parametric cover hooks (activated dynamically for each cover) % Note: text/pre and text/post are invoked inside nt_covers_print_text:n \NTDeclareHook{print/spine/pre} \NTDeclareHook{print/spine/post} \NTDeclareHook{frontmatter/pre} \NTDeclareHook{frontmatter/post} \NTDeclareHook{mainmatter/pre} \NTDeclareHook{mainmatter/post} \NTDeclareHook{backmatter/pre} \NTDeclareHook{backmatter/post} \NTDeclareHook{abstracts/pre} \NTDeclareHook{abstracts/post} \NTDeclareHook{abstract/pre} \NTDeclareHook{abstract/post} \NTDeclareHook{abstract/mid} \NTDeclareHook{abstract/title/before} \NTDeclareHook{abstract/title/after} \NTDeclareHook{listof/pre} \NTDeclareHook{listof/post} \NTDeclareHook{list_of/pre} \NTDeclareHook{list_of/post} \NTDeclareHook{printbib/pre} \NTDeclareHook{printbib/post} \NTDeclareHook{statement/pre} \NTDeclareHook{statement/post} \NTDeclareHook{acknowledgementsblock/pre} \NTDeclareHook{acknowledgementsblock/post} \NTDeclareHook{copyright/pre} \NTDeclareHook{copyright/post} \NTDeclareHook{ntquote/pre} \NTDeclareHook{ntquote/post} \NTDeclareHook{keywords/pre} \NTDeclareHook{keywords/post} % Section-level hooks (used generically via \@nt@printifmaindoc@i) \NTDeclareHook{dedication/pre} \NTDeclareHook{dedication/post} \NTDeclareHook{acknowledgements/pre}\NTDeclareHook{acknowledgements/post} \NTDeclareHook{quote/pre} \NTDeclareHook{quote/post} % Spine hooks (used by uminho school) \NTDeclareHook{spine/pre} \NTDeclareHook{spine/mid} \NTDeclareHook{spine/post} % TEMPLATE CUSTOMIZATION / OPTIONS % Please open and edit the appropriate % configuration file “0-Config/1_novathesis.tex” %============================================================ \input{\DIRCONFIG/1_novathesis} %============================================================ % COMMAND-LINE OVERRIDES % Any \ntsetup options may be given at the command line, % without editing 0-Config/1_novathesis.tex, e.g.: % latexmk -pdflua -usepretex \ % -pretex='\def\ntoverride{doctype=msc,school=uminho/ec,lang=pt}' template % or, with a plain engine: % lualatex -jobname=template '\def\ntoverride{doctype=msc}\input{template}' % These values take precedence over 0-Config/1_novathesis.tex. %============================================================ \ifdefined\ntoverride \ClassInfo{novathesis}{Applying command-line overrides: \ntoverride} \expandafter\ntsetup\expandafter{\ntoverride} % Re-apply "school" so that school-derived macros (e.g. the degree % acronym, which depends on "doctype") are recomputed and consistent, % regardless of the order of the keys given in \ntoverride. \edef\@nt@override@school{school=\option{/novathesis/schoolgiven}} \expandafter\ntsetup\expandafter{\@nt@override@school} \fi \def\@DOCTYPE{\option{/novathesis/doctype}} \def\@DOCSTATUS{\option{/novathesis/docstatus}} \ExplSyntaxOn \xdef\@DOCCLASS{\prop_item:Ne \c__nt_docclass_prop {\@DOCTYPE}} \ExplSyntaxOff \edef\@LANG@COVER{\option{/novathesis/lang/cover}} \edef\@LANG@COPYRIGHT{\option{/novathesis/lang/copyright}} \edef\@LANG@MAIN{\option{/novathesis/lang/main}} \edef\@LANG@MAIN@LONG{\GetLangLong(\@LANG@MAIN)} \@setabstractorder \IfMemVoidT{AbstractOrder}{en}{% \SetAbstractOrder*(en)={en,pt} } \IfMemVoidT{AbstractOrder}{\@LANG@MAIN}{% \SetAbstractOrder*(\@LANG@MAIN)={\@LANG@MAIN,en} } %============================================================ % LOAD ADDITIONAL PACKAGES %============================================================ %%%%% Configure multilingual language support \definecolor{darkblue}{rgb}{0.0,0.08,0.45}% \babeladjust{ autoload.bcp47 = on } \babelprovide[main,import]{\expanded{\@LANG@MAIN@LONG}} % -------------------------------------------------------- % FIX BABEL TRANSLATION % \RequirePackage{babel} % Support for multilingual documents % \RequirePackage{translator} % Support month name translations for pgfcalendar \ntselectlang{\@LANG@MAIN} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Create list of loaded languages %% which will be loaded dynamically by Babel %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \edef\@LANG@LOADED{\@LANG@COVER, \@LANG@COPYRIGHT, \@LANG@MAIN, \GetAbstractOrder(\@LANG@MAIN)} \UniquifyList{\@LANG@LOADED}[\@LANG@LOADED] % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% FIX BABEL %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \input{fix-babel.tex} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Include strings for all the languages %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \@nt@langloaded@reset % DO NOT wrap this loop in \ExplSyntaxOn. \InputIfFileExists reads the .ldf % files at *execution* time, so an active ExplSyntax would apply expl3 catcodes % to their contents, where a space is ignored: every translated string silently % loses its spaces ("O Candidato" -> "OCandidato", and likewise the whole % copyright paragraph). \@for keeps normal catcodes throughout. \@for\mylang:=\@LANG@LOADED\do{% \InputIfFileExists{\DIRSTRINGS/strings-\mylang.ldf}% {\@nt@langloaded@push{\mylang}}% {\ClassError{novathesis} {File not found: '\DIRSTRINGS/strings-\mylang.ldf' file!}% {Add a file with the translations for this language.}}% }% \SetBkmString*(1-1)={\GetBkmString(cover,\@LANG@MAIN)} \SetBkmString*(1-2)={\GetBkmString(incover,\@LANG@MAIN)} \SetBkmString*(2-1)={\GetBkmString(frontpage,\@LANG@MAIN)} \SetBkmString*(2-2)={\GetBkmString(infrontpage,\@LANG@MAIN)} \SetBkmString*(N-1)={\GetBkmString(inbackcover,\@LANG@MAIN)} \SetBkmString*(N-2)={\GetBkmString(backcover,\@LANG@MAIN)} \SetBkmString*(spine)={\GetBkmString(spine,\@LANG@MAIN)} %-------------------------------- % TIKZ \usetikzlibrary{calc} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% DOCUMENT METADATA %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ExplSyntaxOn % -------------------------------------------------------- % Department %============================================================ \NewMemStore { Department } % 1. The Public Command % s = star (*) <= only define if undefined % r() = required ID in parens <= the lang code % m = mandatory value <= the name of the department \NewDocumentCommand { \ntdepartment } { s r() m } { % We pass the star status (boolean) and expanded arguments to the internal logic \nova_process_department:nee { #1 } { #2 } { #3 } } % 2. Internal Logic \cs_new_protected:Npn \nova_process_department:nnn #1 #2 #3 { % Handle the optional ID: if empty/NoValue, use 'default' \tl_set:Nn \l_tmpa_tl { #2 } % Logic Branching \bool_if:nTF { #1 } { % Starred version: Only set if NOT already defined % We check if the 'department' data for this ID is empty/unset \IfMemVoidT { Department } { \l_tmpa_tl } { \MemSet { Department } { \l_tmpa_tl } { #3 } } } { % Unstarred version: Set/Overwrite regardless \MemSet { Department } { \l_tmpa_tl } { #3 } } } % 3. Generate expansion variants \cs_generate_variant:Nn \nova_process_department:nnn { nee } % Scratch variables used across the field-command implementations below. % (\l_tmpa_tl, \l_tmpb_tl, \l_tmpa_seq, \l_tmpb_seq are expl3 kernel pre-declarations.) \tl_new:N \l__nt_tmpc_tl % ───────────────────────────────────────────────────────────────────────────── % \ntmajorfield(*)(lang){ value } — major field of study % ───────────────────────────────────────────────────────────────────────────── % Shared logic for \ntmajorfield / \ntminorfield: set (lang) to , % unconditionally, or only if not already set (star variant). \cs_new_protected:Npn \__nt_set_field_if_star:nnnn #1 #2 #3 #4 { % #1 = star bool, #2 = store name, #3 = lang key, #4 = value \bool_if:nTF { #1 } { \IfMemVoidT { #2 } { #3 } { \MemSet* { #2 } { #3 } { #4 } } } { \MemSet* { #2 } { #3 } { #4 } } } \NewDocumentCommand { \ntmajorfield } { s r() m } { \__nt_set_field_if_star:nnnn { #1 } { MajorField } { #2 } { #3 } } % ───────────────────────────────────────────────────────────────────────────── % \ntminorfield(*)(lang){ value } — minor field of study % ───────────────────────────────────────────────────────────────────────────── \NewDocumentCommand { \ntminorfield } { s r() m } { \__nt_set_field_if_star:nnnn { #1 } { MinorField } { #2 } { #3 } } % ───────────────────────────────────────────────────────────────────────────── % \ntdegreename(*)(lang){ value } — degree / programme name % Prepends DegreeNamePrefix (if defined by the school) and also sets MajorField. % ───────────────────────────────────────────────────────────────────────────── \cs_new_protected:Npn \__nt_set_degreename:nn #1 #2 { \datamatch { \match } { DegreeNamePrefix } (% { \@DOCTYPE,\@DEGREEACR,\@LANG@COVER },% { \@DOCCLASS,\@DEGREEACR,\@LANG@COVER },% { \@DEGREEACR,\@LANG@COVER },% { \@DOCTYPE,\@LANG@COVER },% { \@DOCCLASS,\@LANG@COVER },% { \@LANG@COVER } % ) % \ifblank { \match } { \MemSet* { DegreeName } { #1 } { #2 } } { \MemSet* { DegreeName } { #1 } { \match\ #2 } } % \MemSet* { MajorField } { #1 } { #2 } % } \NewDocumentCommand { \ntdegreename } { s r() m } { \bool_if:nTF { #1 } { \IfMemVoidT { DegreeName } { #2 } { \__nt_set_degreename:nn { #2 } { #3 } } } { \__nt_set_degreename:nn { #2 } { #3 } } } % ───────────────────────────────────────────────────────────────────────────── % \ntspecialization(*)(lang){ value } — specialization track % Prepends SpecializationString (if defined) and also sets MinorField. % ───────────────────────────────────────────────────────────────────────────── \cs_new_protected:Npn \__nt_set_specialization:nn #1 #2 { \datamatch { \specmatch } { SpecializationString } (% { \@DOCTYPE,\@DEGREEACR,\@LANG@COVER },% { \@DOCCLASS,\@DEGREEACR,\@LANG@COVER },% { \@DEGREEACR,\@LANG@COVER },% { \@DOCTYPE,\@LANG@COVER },% { \@DOCCLASS,\@LANG@COVER },% { \@LANG@COVER } % ) % \ifblank { \specmatch } { \MemSet* { Specialization } { #1 } { #2 } } { \MemSet* { Specialization } { #1 } { \specmatch\ #2 } } % \MemSet* { MinorField } { #1 } { #2 } % } \NewDocumentCommand { \ntspecialization } { s r() m } { \bool_if:nTF { #1 } { \IfMemVoidT { MinorField } { #2 } { \__nt_set_specialization:nn { #2 } { #3 } } } { \__nt_set_specialization:nn { #2 } { #3 } } } % ───────────────────────────────────────────────────────────────────────────── % \ntsponsors(order,type,lang){ value } — funding sponsor entry % Parens hold three comma-separated fields: display order, content type % (logo/text), and language code. % Bug-fix: old code stored the "type" field as the value instead of the % mandatory {value} argument (now #2). % ───────────────────────────────────────────────────────────────────────────── \NewDocumentCommand { \ntsponsors } { r() m } { % Split "(order,type,lang)" on comma \seq_set_split:Nnn \l_tmpa_seq { , } { #1 } \tl_set:Ne \l_tmpa_tl { \seq_item:Nn \l_tmpa_seq { 1 } } % order \tl_set:Ne \l_tmpb_tl { \seq_item:Nn \l_tmpa_seq { 2 } } % type \tl_set:Ne \l__nt_tmpc_tl { \seq_item:Nn \l_tmpa_seq { 3 } } % lang \MemSet* { Sponsor } { \l__nt_tmpc_tl , \l_tmpa_tl , \l_tmpb_tl } { #2 } } % ───────────────────────────────────────────────────────────────────────────── % \nttitle(type,lang){ value } — document title % Also stores a plain-text variant (no line-break commands) and, for type=main, % sets the spine title to the same plain value. % ───────────────────────────────────────────────────────────────────────────── \NewDocumentCommand { \nttitle } { r() m } { % Split "(type,lang)" on comma \seq_set_split:Nnn \l_tmpa_seq { , } { #1 } \tl_set:Ne \l_tmpa_tl { \seq_item:Nn \l_tmpa_seq { 1 } } % type \tl_set:Ne \l_tmpb_tl { \seq_item:Nn \l_tmpa_seq { 2 } } % lang \MemSet* { DocTitle } { \l_tmpb_tl , \l_tmpa_tl } { #2 } \NewlineToSpace { #2 } [ \l__nt_tmpc_tl ] \MemSet* { DocTitle } { \l_tmpb_tl , \l_tmpa_tl , plain } { \l__nt_tmpc_tl } \str_if_eq:eeTF { \l_tmpa_tl } { main } { \MemSet* { DocTitle } { \l_tmpb_tl , spine } { \l__nt_tmpc_tl } } { } } % Define a temporary token list variable \tl_new:N \l__memory_clean_tl \NewDocumentCommand { \NewlineToSpace } { m o } { % 1. Store the input (#1) into the variable \tl_set:Nn \l__memory_clean_tl { #1 } % 2. Perform the replacement. % In expl3, ~ represents a space token (catcode 10). % This replaces every occurrence of the token \\ with a space. \tl_replace_all:Nnn \l__memory_clean_tl { ~\\~ } { ~ } \tl_replace_all:Nnn \l__memory_clean_tl { ~\\ } { ~ } \tl_replace_all:Nnn \l__memory_clean_tl { \\~ } { ~ } \tl_replace_all:Nnn \l__memory_clean_tl { \\ } { ~ } % 3. Check if the optional argument (#2) is provided \IfNoValueTF { #2 } { % If no optional arg: Output the result directly \tl_use:N \l__memory_clean_tl } { % If optional arg exists: Set the provided macro (#2) to the result \tl_set_eq:NN #2 \l__memory_clean_tl } } % \PrintDateISO { 2022-12-25 } -> localized date, e.g., December 20, 2022; 20 de dezembro de 2022 % \PrintDateISO { 2022-12 } -> e.g., December 20, 2022; Dezembro, 2022 % \PrintDateISO { 2022 } -> e.g., 2022 % \PrintDateISO*{ 2022-12 } -> e.g., DECEMBER, 2022 (starred = uppercase the month name) % % \nt_print_iso_date:nnn's own #2/#3 (separator/date string) are typeset % directly by a \cs_new_protected: function, so they're opaque to % \MakeUppercase -- \MakeUppercase{\PrintDateISO[~]{...}} silently does % nothing, since \MakeUppercase can only see through fully expandable macros, % and a protected function is deliberately immune to that kind of expansion. % Wrapping just the already-expanded month name (\l_tmpa_tl, plain text by % the time #1 is applied to it) from *inside* the protected function sidesteps % that entirely, so the starred form does the right thing directly. \NewDocumentCommand { \PrintDateISO } { s O{,~} m } { \IfBooleanTF { #1 } { \nt_print_iso_date:nnn { \MakeUppercase } { #2 } { #3 } } { \nt_print_iso_date:nnn { } { #2 } { #3 } } } % Sequential variables to store Y, M, D \seq_new:N \l_nt_date_seq % Generate the 'Nne' variant (N = seq, n = delimiter, e = fully-expanded string) \cs_generate_variant:Nn \seq_set_split:Nnn { Nne } \cs_new_protected:Nn \nt_print_iso_date:nnn { % Split the input string by the hyphen (-) \seq_set_split:Nne \l_nt_date_seq { - } { #3 } \int_case:nn { \seq_count:N \l_nt_date_seq } { % Case 1: Only Year (YYYY) { 1 } { \seq_item:Nn \l_nt_date_seq { 1 } } % Case 2: Year and Month (YYYY-MM) { 2 } { \tl_set:Ne \l_tmpa_tl { \babelmonthname { \seq_item:Nn \l_nt_date_seq { 2 } } } \nt_titlecase_first:N \l_tmpa_tl #1 { \tl_use:N \l_tmpa_tl } #2 % separator \seq_item:Nn \l_nt_date_seq { 1 } % year } % Case 3: Full Date (YYYY-MM-DD) { 3 } { \localedate { \seq_item:Nn \l_nt_date_seq { 1 } } { \seq_item:Nn \l_nt_date_seq { 2 } } { \seq_item:Nn \l_nt_date_seq { 3 } } } } } % Define the command with an optional d() argument and a mandatory m argument \NewDocumentCommand { \SetDateISO } { d() m } { \nt_set_iso_date:nn { #1 } { #2 } } % Sequential variable to store the split parts \seq_new:N \l_nt_parts_seq \cs_new_protected:Nn \nt_set_iso_date:nn { % 1. Store the raw ISO string \MemSet { DocDate } { #1 } { #2 } % 2. Split the string by the hyphen \seq_set_split:Nnn \l_nt_parts_seq { - } { #2 } % 3. Process based on how many parts were found \int_case:nn { \seq_count:N \l_nt_parts_seq } { % Case: YYYY { 1 } { \MemSet* { DocDate } { #1, year } { \seq_item:Nn \l_nt_parts_seq { 1 } } } % Case: YYYY-MM { 2 } { \MemSet* { DocDate } { #1, year } { \seq_item:Nn \l_nt_parts_seq { 1 } } \MemSet* { DocDate } { #1, month } { \seq_item:Nn \l_nt_parts_seq { 2 } } % Use Babel's \monthname to get the localized text \MemSet* { DocDate } { #1, month, text } { \babelmonthname { \seq_item:Nn \l_nt_parts_seq { 2 } } } } % Case: YYYY-MM-DD { 3 } { \MemSet* { DocDate } { #1, year } { \seq_item:Nn \l_nt_parts_seq { 1 } } \MemSet* { DocDate } { #1, month } { \seq_item:Nn \l_nt_parts_seq { 2 } } \MemSet* { DocDate } { #1, month, text } { \babelmonthname { \seq_item:Nn \l_nt_parts_seq { 2 } } } \MemSet* { DocDate } { #1, day } { \seq_item:Nn \l_nt_parts_seq { 3 } } } } } \ExplSyntaxOff \NewMemStore{DocDate} \let\ntdate\SetDateISO \SetDateISO(submission){2000-01-31} \SetDateISO(exam){2000-01-31} %============================================================ % Author identification %============================================================ \NewMemStore{DocAuthor} \SetDocAuthor*(name)={Author Name} \SetDocAuthor*(name,short)={Author Short Name} \SetDocAuthor*(gender)={Author Gender} \SetDocAuthor*(degree,\@LANG@COVER)={Author Previous Degree} % ───────────────────────────────────────────────────────────────────────────── % \ntauthorname(gender){Full Name}{Short Name} % \ntauthordegree(lang){previous degree name} % ───────────────────────────────────────────────────────────────────────────── \NewDocumentCommand{\ntauthorname}{ r() m m } { % #1 = gender (m/f), #2 = full name, #3 = short name \MemSet*{DocAuthor}{gender}{#1} \MemSet*{DocAuthor}{name}{#2} \MemSet*{DocAuthor}{name,short}{#3} } \NewDocumentCommand{\ntauthordegree}{ r() m } { % #1 = lang, #2 = previous degree name \MemSet*{DocAuthor}{degree,#1}{#2} } %============================================================ % Setting cover defaults %============================================================ % strings to be defined for each language \nttitle(main,\@LANG@COVER){\GetDefaultNtTitle(\@LANG@COVER)} \ntdepartment(\@LANG@COVER){\GetDefaultNtDepartment(\@LANG@COVER)} \ntdegreename(\@LANG@COVER){\GetDefaultNtDegreeName(\@LANG@COVER)} % "Other lists" (listoffigures/listoftables/.../custom) registered per % matter (frontmatter/backmatter, or any key \ntaddlistof/print/otherlists % names -- not a small fixed set like the print-order buckets above, so % the seq is created lazily on first push, mirroring options-ext.sty's % old ".newpush" semantics exactly). Plain-named (no "_"/":") so % \ntaddlistof's classical body (see the note on it below) can push % without ExplSyntaxOn active at the call site. \ExplSyntaxOn \cs_new_protected:Npn \@nt@listof@push #1#2 { \seq_if_exist:cF { g__nt_listof_#1_seq } { \seq_new:c { g__nt_listof_#1_seq } } \seq_gput_right:cn { g__nt_listof_#1_seq } {#2} } % \@nt@listof@ifdefined{}{}{} -- like \ifoptiondefined % used to be for this registry. \cs_new_protected:Npn \@nt@listof@ifdefined #1 { \seq_if_exist:cTF { g__nt_listof_#1_seq } } % \@nt@listof@run{}{} -- % same "no :c variant of seq_map_inline" situation as % \@nt@printorder@run above; same fix. \cs_new_protected:Npn \@nt@listof@run #1#2 { \expandafter\seq_map_inline:Nn\csname g__nt_listof_#1_seq\endcsname {#2} } \ExplSyntaxOff %============================================================ % Adding list_of % NOTE: kept in LaTeX2e syntax (\IfStrEqCase, not expl3's \str_case:nnF). % The branches below embed literal prose in \ClassError messages, and under % \ExplSyntaxOn every space in that prose would be swallowed % ("Can'tmakelistoflistings."). Not worth an ExplSyntax block here. \newcommand*{\ntaddlistof}[2][]{% % #2 = the list of SOMETHING without the initial "\" \ifoptioncontains{/novathesis/listof/skip}{#2}{}{% \@ifmtarg{#1}{% \edef\@listofat{\option{/novathesis/print/otherlists}}% }{% \edef\@listofat{#1}% } % \typeout{\ISTOF 1=[\@listofat] 2=[#2]}\NTADDLISTOF% \IfStrEqCase{#2}{% {listoffigures}{\@nt@listof@push{\@listofat}{% \clearforchapter% \listoffigures }}% {listoftables}{\@nt@listof@push{\@listofat}{% \clearforchapter% \listoftables }}% {listoflistings}{\@nt@listof@push{\@listofat}{% \ifcsdef{listoflistings}{% \clearforchapter% \phantomsection \bookmark[level=\@nt@lol@bkm@level, dest=\HyperLocalCurrentHref]{\listoflistingscaption} \listoflistings }{% \ClassError{novathesis}{Can't make list of listings. Please report this problem in the 'novathesis' github. Thanks!}{}% }% }}% {listofalgorithms}{\@nt@listof@push{\@listofat}{% \clearforchapter% \phantomsection \ifcsdef{listalgorithmname}{% \bookmark[level=\@nt@lol@bkm@level, dest=\HyperLocalCurrentHref]{\listalgorithmname} }{% \ifcsdef{listalgorithmcfname}{% \bookmark[level=\@nt@lol@bkm@level, dest=\HyperLocalCurrentHref]{\listalgorithmcfname} }{% \ClassError{novathesis} {Cannot make list of algorithms. Please report this problem in the 'novathesis' github. Thanks!}{}% }% }% \listofalgorithms }}% }[% \clearforchapter \@nt@listof@push{\@listofat}{% \ifcsdef{#2}{% \csuse{#2}% }{% \ClassError{novathesis} {Cannot make #2. Please report this problem in the 'novathesis' github. Thanks!}{}% }% }% ]% }% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% STRUCTURAL PRINTING ENGINE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %============================================================ % Print document “parts/sections/regions” % Kept in LaTeX2e syntax for the same reason as \ntaddlistof above: the % branches carry literal text, which \ExplSyntaxOn would strip spaces from. \newcommand*{\ntprint}[1]{% \IfStrEqCase{#1}{% {frontcover}{% \thispagestyle{empty}% \pagestyle{empty}% \ntprintcovers% }% {frontmatter}{% \ntthesisfrontmatter% Before the main text (TOC, etc) — Roman page numbering \phantomsection \bookmark[level=0, dest=\HyperLocalCurrentHref]{\GetBkmString(frontmatter,\@LANG@MAIN)} % Nest all front-matter items under the "Front Matter" bookmark node. % \@nt@bkm@level=1 shifts \ChapterNoTitle pages (copyright, dedication, …) % to level 1; \shiftbookmarks shifts chapter-level items (list-ofs) likewise. % \bookmark[level=0]{Contents} and \bookmark[level=0]{List of…} use explicit % levels so they stay at level 0 and are unaffected by \shiftbookmarks. \begingroup \def\@nt@bkm@level{1}% \shiftbookmarks{\ntprintlist{#1_\@DOCSTATUS}}% \endgroup }% {mainmatter}{% \ntthesismainmatter% Main text — Arabic page numbering \thispagestyle{novathesis@mainmatter}% \pagestyle{novathesis@mainmatter}% \ntprintlist{#1}% }% {backmatter}{% \ntthesisbackmatter % The back text — Arabic page numbering \phantomsection % level=-1 (not 0): "Front Matter" gets away with level=0 only because % nothing is open yet at a shallower level when it's written. By the % time "Back Matter" is written, a \part (level -1) may still be the % open ancestor, and a level=0 sibling of chapters would nest inside % it instead of popping back out to the top level. -1 matches \part's % own level, so this always closes back out to the top -- whether or % not the document uses \part at all (with no open ancestor at -1 or % shallower, a level=-1 bookmark still becomes a plain root, exactly % as level=0 did before in the no-\part case). \bookmark[level=-1, dest=\HyperLocalCurrentHref]{\GetBkmString(backmatter,\@LANG@MAIN)} \shiftbookmarks{\ntprintlist{#1}}% }% {backcover}{% \thispagestyle{empty}% \pagestyle{empty}% \ntprintbackcover% }% }[\ifcsmacro{ntprint#1}{\csuse{ntprint#1}}{\ifcsmacro{#1}{\csuse{#1}}{}}]% } % Print-order registries: which sections print, and in what order, for % each of frontmatter (per docstatus)/mainmatter/backmatter. Were 5 % options-package lists (seeded with a default order, some fully % replaced by school .clo files wanting a custom one); now 5 plain % seqs. \@nt@printorder@set/@run are plain-named (no "_"/":") so % classical code -- including every school .clo file -- can call them % without needing ExplSyntaxOn active at the call site. \ExplSyntaxOn \seq_new:N \g__nt_print_frontmatter_final_seq \seq_new:N \g__nt_print_frontmatter_provisional_seq \seq_new:N \g__nt_print_frontmatter_working_seq \seq_new:N \g__nt_print_mainmatter_seq \seq_new:N \g__nt_print_backmatter_seq % \@nt@printorder@set{}{} -- (re)set the print % order for (one of frontmatter_final, frontmatter_provisional, % frontmatter_working, mainmatter, backmatter) to the given comma-list. % Used both for the default declarations below and by school .clo files % that want a fully custom order; the "set" semantics (full replace, % not append) match \options{.../key = {...}}'s old behaviour exactly. \cs_new_protected:Npn \@nt@printorder@set #1#2 { \seq_set_from_clist:cn { g__nt_print_#1_seq } {#2} } % \@nt@printorder@run{}{} % -- run once per item registered under , in order. % l3seq has no generated ":c" variant of seq_map_inline (confirmed by % testing directly -- unlike clist/seq_new, _gput_right, etc., which do), % so the csname is built with the plain \csname/\expandafter primitives % instead, which work identically regardless of ExplSyntaxOn state. \cs_new_protected:Npn \@nt@printorder@run #1#2 { \expandafter\seq_map_inline:Nn\csname g__nt_print_#1_seq\endcsname {#2} } \ExplSyntaxOff \newcommand*{\ntprintlist}[1]{% \@nt@printorder@run{#1}{% \begingroup \clearpage \ifcsmacro{ntprint##1}{% \ntprint#1 is defined % \bookmarksetupnext{rellevel=1}% \NTRunHook{ntprint##1/pre}\csuse{ntprint##1}\NTRunHook{ntprint##1/post}% }{% \ntprint#1 is undefined \ifcsmacro{##1}{% \##1 is defined % \bookmarksetupnext{rellevel=1}% \NTRunHook{##1/pre}\csuse{##1}\NTRunHook{##1/post}% }{% nothing is defined \ClassError{novathesis}{Invalid contents for frontmatter or mainmatter: [##1]}{}% }% }% % \unskip% \clearforchapter% \ignorespaces% \endgroup }% } % \ifoptionequal/\if@backmatter/\forallglossaries/\forglsentries/ % \printunsrtglossary are plain classical control sequences (no "_"/":" % in their names), so they can be called freely from inside this expl3 % body. The listtypes registry check, the string comparison, and the % not-empty flag (formerly a classical \newif) all move to expl3; none % of this carries typeset prose -- "frontmatter"/"backmatter" are % internal keywords, not document text. \ExplSyntaxOn \bool_new:N \l__nt_glossary_nonempty_bool % Per-type title override lookup (glossaries/titles, see nt-core.sty). % Parses the "type=Title,type2=Title2,..." option value on every call % rather than caching it, since \ntsetup may run again between calls % (e.g. a school .clo customizing it after the class default is set). \clist_new:N \l__nt_glstitle_clist \seq_new:N \l__nt_glstitle_pair_seq \tl_new:N \l__nt_glstitle_key_tl \tl_new:N \l__nt_glstitle_result_tl \tl_new:N \l__nt_glstype_tl % bib2gls's internal name for the main (undeclared-type) glossary is "main", % not "glossary" -- but \ntaddfile{glossaries}[glossary]{...} is how users % register its source files, so accept "glossary" as an alias for "main" in % glossaries/groupheadings and glossaries/titles, matching that file-key. \cs_new_protected:Npn \@nt@glstype_alias:n #1 % #1 = glossary type, already expanded { \str_if_eq:eeTF {#1} {main} { \tl_set:Nn \l__nt_glstype_tl {glossary} } { \tl_set:Nn \l__nt_glstype_tl {#1} } } \cs_new_protected:Npn \@nt@glstitle_lookup:n #1 % #1 = glossary type, already expanded { \tl_clear:N \l__nt_glstitle_result_tl \clist_set:Ne \l__nt_glstitle_clist { \option{/novathesis/glossaries/titles} } \clist_map_inline:Nn \l__nt_glstitle_clist { \seq_set_split:Nnn \l__nt_glstitle_pair_seq {=} {##1} \int_compare:nNnT { \seq_count:N \l__nt_glstitle_pair_seq } = {2} { \tl_set:Ne \l__nt_glstitle_key_tl { \seq_item:Nn \l__nt_glstitle_pair_seq {1} } \tl_trim_spaces:N \l__nt_glstitle_key_tl \str_if_eq:eeT {#1} { \l__nt_glstitle_key_tl } { \tl_set:Ne \l__nt_glstitle_result_tl { \seq_item:Nn \l__nt_glstitle_pair_seq {2} } \tl_trim_spaces:N \l__nt_glstitle_result_tl } } } } \cs_new_protected:Npn \myprintglossaries { % "glossaries" in listof/skip is just a friendlier spelling of % print/glossaries=false -- there being no \ntaddlistof entry for % glossaries to skip in the first place, unlike listoffigures & co. \ifoptioncontains {/novathesis/listof/skip} {glossaries} { \ntsetup{print/glossaries=false} } { } % ignore if no glossaries were defined \seq_if_in:NnTF \g__nt_listtypes_seq {glossaries} { \ifoptionequal {/novathesis/print/glossaries} {false} { } { \if@backmatter \def \@matter {backmatter} \else \def \@matter {frontmatter} \fi \str_if_eq:eeTF { \option{/novathesis/print/glossaries} } { \@matter } { \forallglossaries {\thisglossary} { \bool_set_false:N \l__nt_glossary_nonempty_bool \forglsentries [\thisglossary] {\thisentry} { \bool_set_true:N \l__nt_glossary_nonempty_bool } \bool_if:NT \l__nt_glossary_nonempty_bool { \group_begin: \exp_args:Ne \@nt@glstype_alias:n {\thisglossary} \ifoptioncontains {/novathesis/glossaries/groupheadings} {\l__nt_glstype_tl} { } { \renewcommand*{\glsgroupheading}[1]{} } \exp_args:Ne \@nt@glstitle_lookup:n {\l__nt_glstype_tl} \tl_if_empty:NTF \l__nt_glstitle_result_tl { \printunsrtglossary [type=\thisglossary] } { \printunsrtglossary [ type=\thisglossary, title={\tl_use:N \l__nt_glstitle_result_tl} ] } \group_end: } } } { } } } { } } \ExplSyntaxOff % -------------------------------------------------------- % DEFAULT VALUES FOR frontmatter AND mainmatter \@nt@printorder@set{frontmatter_final}{% statement, % The statement page copyright, % (*) The copyright page dedication, % (*) Print the dedication acknowledgements, % (*) Print the acknowledgments quote, % (*) Print the quote abstracts, % Print abstracts in multiple languages. aidisclose, % AI disclosure statement alllistof, % Print all the listof defined in “6_list_of.tex” myprintglossaries, % Print the Glossary, Acronyms, Symbols, etc… } \@nt@printorder@set{frontmatter_provisional}{ statement, % The statement page copyright, % (*) The copyright page dedication, % (*) Print the dedication acknowledgements, % (*) Print the acknowledgments quote, % (*) Print the quote abstracts, % Print abstracts in multiple languages. aidisclose, % AI disclosure statement alllistof, % Print all the listof defined in “6_list_of.tex” myprintglossaries, % Print the Glossary, Acronyms, Symbols, etc… } \@nt@printorder@set{frontmatter_working}{ abstracts, % Print abstracts in multiple languages. aidisclose, % AI disclosure statement alllistof, % Print all the listof defined in “6_list_of.tex” myprintglossaries, % Print the Glossary, Acronyms, Symbols, etc… } \@nt@printorder@set{mainmatter}{ chapters, % Print document chapters }% \ifoptionequal{/novathesis/print/webography}{}{% \@nt@printorder@set{backmatter}{ bibsingle, % Print the bibliography alllistof, % Print all the listof defined in “6_list_of.tex” myprintglossaries, % Print the Glossary, Acronyms, Symbols, etc… appendices, % Print appendices, if any! annexes, % Print annexes, if any! index, % Print the index colophon, % Print the Colophon page }% }{% \@nt@printorder@set{backmatter}{ bibseparate, % Print the web references separate from the remainder of the bibliography alllistof, % Print all the listof defined in “6_list_of.tex” myprintglossaries, % Print the Glossary, Acronyms, Symbols, etc… appendices, % Print appendices, if any! annexes, % Print annexes, if any! index, % Print the index colophon, % Print the Colophon page }% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% SCHOOL & UNIVERSITY LOGIC %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Update Schoold's images folder %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ntfor\match:={\@UNIV,\@UNIV/\@SCHL}\do{% \IfFileExists{\DIRSCHOOLS/\match/Images/DO_NOT_REMOVE_THIS_FILE.txt}{% \prependtographicspath{{\DIRSCHOOLS/\match/Images/},}}{}% } %============================================================ % UNIVERSITY/SCHOOL SPECIFIC MATERIALS %============================================================ \InputIfFileExists{\DIRSCHOOLS/\@UNIV/\@UNIV-defaults.clo} {} {\ClassError{novathesis} {Missing file '\DIRSCHOOLS/\@UNIV/\@UNIV-defaults.clo'}{}} \IfFileExistsCase [\DIRSCHOOLS/\@UNIV/\@SCHL/] { {\@UNIV-\@SCHL-\@DEGREEACR-defaults.clo}{\input{\ntfoundpath}}, {\@UNIV-\@SCHL-defaults.clo}{\input{\ntfoundpath}}, } { \ClassError{novathesis} {Missing file '\DIRSCHOOLS/\@UNIV/\@SCHL/\@UNIV-\@SCHL-defaults.clo'} {} } \ValidateLtxProcessor{\@UNIV}{\@SCHL}{\@DEGREEACR} \ValidateDegree{\@UNIV}{\@SCHL}{\@DEGREEACR} \def\@ntsetuplevel{} % Now we can load biblatx \NTRunHook{afterloading/schoolconfig} % Prefer: DOI, else eprint, else URL \renewbibmacro*{doi+eprint+url}{% \iffieldundef{doi} {% \iffieldundef{eprint} {\usebibmacro{url+urldate}}% no doi/eprint → URL (with date if available) {\usebibmacro{eprint}}% no doi, but eprint → eprint }% {\printfield{doi}}% doi present → DOI } % -------------------------------------------------------- % Customize the pagestyle \newcommand{\rightorleftmark}{% \setbox0=\hbox{\rightmark} \ifdim\wd0>0.1pt\relax \rightmark \else \leftmark \fi } \makepagestyle{novathesis@mainmatter} \makeoddfoot{novathesis@mainmatter}{}{\thepage}{} \makeevenfoot{novathesis@mainmatter}{}{\thepage}{} \makeheadrule{novathesis@mainmatter}{\textwidth}{\normalrulethickness} \makeevenhead{novathesis@mainmatter}{\small\textsc{\leftmark}}{}{} \makeoddhead{novathesis@mainmatter}{}{}{\small\rightorleftmark} \makepagestyle{novathesis@frontmatter} \makeoddfoot{novathesis@frontmatter}{}{\thepage}{} \makeevenfoot{novathesis@frontmatter}{}{\thepage}{} \ifoptionequal{/novathesis/media}{paper}{ \ntsetup{color/links=Black} \openright }{ \openany } % -------------------------------------------------------- % If option “debug={index}” option is active, % highlight index keywords in the main text \providecommand*{\debugindexcolor}{red!50} \newcommand{\showlabelsinline}[2]{% \setbox0=\hbox{\fcolorbox{\debugindexcolor}{white}{\tiny#1#2}}% \marginpar{\copy0}% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% LOADING CUSTOMIZATION STUFF - part 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \AtEndPreamble{ \iftoggle{/novathesis/print/index}{% \makeindex[intoc,columns=2,options=-s \DIRNTFILES/ntindexstyle]% }{}% } %============================================================ % THESIS/DISSERTATION COVER DATA (title, author, etc) % Please open and edit the appropriate % configuration file “0-Config/3_cover.tex” % configuration file “0-Config/9__.tex” %============================================================ \ntselectlang{\@LANG@COVER}% \input{\DIRCONFIG/3_cover} % \NTRunHook{cover} \IfFileExists{\DIRCONFIG/9_\@UNIV_\@SCHL.tex} {\def\@ntsetuplevel{\@UNIV/\@SCHL/}\input{\DIRCONFIG/9_\@UNIV_\@SCHL.tex}} {\def\@ntsetuplevel{\@UNIV/}\InputIfFileExists{\DIRCONFIG/9_\@UNIV.tex}{}{}} %============================================================ % THESIS/DISSERTATION FILES % Please open and edit the appropriate % configuration file “0-Config/4_files.tex” %============================================================ \input{\DIRCONFIG/4_files} \ntaddfile{bib}{\DIRSTYFILES/fix-bib.bib} % \NTRunHook{files} %============================================================ % ADDITIONAL PACKAGES and MACROS % Please open and edit the appropriate % configuration file “0-Config/8_packages.tex” %============================================================ % \NTRunHook{packages/pre} \AtEndPreamble{\input{\DIRCONFIG/5_packages}} % \NTRunHook{packages/post} %============================================================ % WHICH LIST_OF TO PRINT % Please open and edit the appropriate % configuration file “0-Config/6_list_of.tex” %============================================================ \AtEndPreamble{ % is only loaded after school's configuration % can be changhed with "\ntsetup{print/other}" \makeatletter \NTRunHook{list_of/pre} \input{\DIRCONFIG/6_list_of} \NTRunHook{list_of/post} } %============================================================ % Deal with AI disclose declaration %============================================================ \AtEndPreamble{ \ifoptionequal{/novathesis/print/aidisclosure}{aidisclose}{ \input{\DIRCONFIG/7-aidisclose} }{\gdef\aidversion{0.0.0}} } %============================================================ \setcounter{biburlnumpenalty}{100}% Allow to break DOIs in bibliography \ExplSyntaxOn \seq_if_exist:cT { g__nt_filereg/@nt/file/bib/\@DOCTYPE } { \expandafter\seq_map_inline:Nn\csname g__nt_filereg/@nt/file/bib/\@DOCTYPE\endcsname { \addbibresource{#1} } } \ExplSyntaxOff \ifdocunset{\ntsetup{docstatus=working}}{} \ifoptionequal{/novathesis/spine/layout}{unset} {\ifdocfinal{\ifmaindoc{\ntsetup{spine/layout=trim}} {\ntsetup{spine/layout=false}}} {\ntsetup{spine/layout=false}}} {} \ifdocfinal{\ntsetup{print/committee=true}}{} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ExplSyntaxOn \newcommand{\@nt@loadallfiles}[2]{% \seq_if_exist:cT { g__nt_filereg/@nt/file/#2/#1 } { \expandafter\seq_map_inline:Nn\csname g__nt_filereg/@nt/file/#2/#1\endcsname {\@ntloadfile@i{##1}} }% } \ExplSyntaxOff \newcommand{\@ntloadfile@i}[2][]{% \InputIfFileExists{#2}{}{#1}} \NewDocumentCommand{\PrintAddedFile}{O{\@DOCTYPE} m}{% % #1=KEY % #2=file class % #3=optional bookmark level \iffileadded[#1]{#2} {\@nt@loadallfiles{#1}{#2}} {}% } \ExplSyntaxOn \newcommand{\iffileadded}[2][\@DOCTYPE]{% \seq_if_exist:cTF { g__nt_filereg/@nt/file/#2/#1 }} \ExplSyntaxOff % -------------------------------------------------------- % LOAD A DEFAULT COPYRIGHT PAGE DEFINITION \newcommand{\@nt@AddFileIfExists}[1]{% % #1 = class % #2 = sub class [OPTIONAL] % #3 = file name % #4 = dir list % #5 = action if not found [OPTIONAL] \@ifnextchar[{\@nt@AddFileIfExists@i{#1}}{\@nt@AddFileIfExists@i{#1}[\@DOCTYPE]}% } \def\@nt@AddFileIfExists@i#1[#2]#3#4{% \@ifnextchar[{\@nt@AddFileIfExists@ii{#1}[#2]{#3}#4}{\@nt@AddFileIfExists@ii{#1}[#2]{#3}#4[]}% } \long\def\@nt@AddFileIfExists@ii#1[#2]#3#4[#5]{% \ntfor\arg:=#4\do{\IfFileExists{\arg#3}{\ntaddfile{#1}[#2]{\arg#3}\ntforbreak}{}}[#5]% } \InputIfFileExistsInDirsTF {nt-spine.sty} {% {\DIRSCHOOLS/\@UNIV/\@SCHL}, {\DIRSCHOOLS/\@UNIV}, {\DIRSTYFILES}, } {} % true {\ClassError{novathesis}{No 'nt-spine' file found.}{}}% \ifoptionequal{/novathesis/spine/layout}{false} {}% skip the spine {% print the spine \ifmaindoc{\AtEndDocument{\csuse{ntprintspine}}}{}% }