From 6e5604705e34b3cf736b09c3987d7f54e1202af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Mekina?= Date: Fri, 10 Oct 2025 17:42:03 +0200 Subject: [PATCH] extract arguments and add title pages disabling --- template/arguments.typ | 174 +++++++++++++++++++++++++++++++++++ template/classic/bp.typ | 71 +++++++------- template/classic/classic.typ | 51 ++++------ template/classic/common.typ | 64 ++++++++----- template/classic/dp.typ | 67 +++++++------- template/classic/other.typ | 24 ++--- template/template.typ | 60 +++++------- template/utils.typ | 8 ++ 8 files changed, 338 insertions(+), 181 deletions(-) create mode 100644 template/arguments.typ diff --git a/template/arguments.typ b/template/arguments.typ new file mode 100644 index 0000000..0b41311 --- /dev/null +++ b/template/arguments.typ @@ -0,0 +1,174 @@ +#import "utils.typ": assert_type_signature, is_none, map_none, deref + +#let arguments_structure = ( + document: ( + visual_style: "string", + faculty: "string", + language: "string", + type: "string", + ), + title_pages: "string | boolean | none", + title: "dictionary[string : string] | none", + author: ( + name: "string | none", + pronouns: "string | none", + programme: "dictionary[string : string] | none", + specialization: "dictionary[string : string] | none", + year_of_study: "integer | none", + ), + project: ( + supervisor: "string | dictionary[string : string] | none", + consultant: "string | dictionary[string : string] | none", + ), + abstract: ( + content: "dictionary[string : string | content] | none", + keywords: "dictionary[string : array[string]] | none", + ), + acknowledgement: "dictionary[string : string | content] | none", + assignment: "string | none", + citations: "string", +); + + +#let check_arguments(args) = { + let check_arguments_dict(structure, args, argument_path) = { + for (key, value) in structure.pairs() { + argument_path.push(str(key).replace("_", " ")); + + if not key in args { + panic("invalid arguments definition"); + } + let arg = args.at(key); + + if type(value) == dictionary { + check_arguments_dict(value, arg, argument_path); + } else if type(value) == str { + assert_type_signature(arg, value, argument_path.join(" ")); + } else { + panic("invalid arguments definition"); + } + + let _ = argument_path.pop(); + } + } + + check_arguments_dict(arguments_structure, args, ()); +} + +#let get_arg_single(args, path) = { + let args = args; + for segment in path.split(".") { + if segment not in args { + panic("invalid argument query path: " + str(path)); + } + args = args.at(segment); + } + args +} + +#let get_arg(args, path) = { + if type(path) == array { + let res = (); + for path in path { + res.push(get_arg_single(args, path)); + } + res + } else if type(path) == str { + get_arg_single(args, path) + } else { + panic("invalid argument path"); + } +} + +#let req_arg_single(args, path) = { + let arg = get_arg_single(args, path); + if is_none(arg) { + let panic_message = path.split(".").join(" ").replace("_", " ") + " is missing"; + panic(panic_message); + } + arg +} + +#let req_arg(args, path) = { + if type(path) == array { + let res = (); + for path in path { + res.push(req_arg_single(args, path)); + } + res + } else if type(path) == str { + req_arg_single(args, path) + } else { + panic("invalid argument path"); + } +} + +#let map_arg_single(args, path, mapper) = { + let arg = get_arg(args, path); + map_none(arg, mapper) +} + +#let map_arg(args, path, mapper) = { + if type(path) == array { + let res = (); + for path in path { + res.push(map_arg_single(args, path, mapper)); + } + res + } else if type(path) == str { + map_arg_single(args, path, mapper) + } else { + panic("invalid argument path"); + } +} + +#let arguments( + document_info, + title_pages, + title, + author_info, + project_info, + abstract_info, + acknowledgement, + assignment, + citations, +) = { + ( + document: document_info, + title_pages: title_pages, + title: title, + author: author_info, + project: project_info, + abstract: abstract_info, + acknowledgement: acknowledgement, + assignment: assignment, + citations: citations, + ) +} + +#let document_info(visual_style, faculty_abbreviation, language_abbreviation, document_type) = { + ( + visual_style: visual_style, + faculty: faculty_abbreviation, + language: language_abbreviation, + type: document_type, + ) +} + +#let author_info(name, pronouns, programme, specialization, year_of_study) = { + ( + name: name, + pronouns: pronouns, + programme: programme, + specialization: specialization, + year_of_study: year_of_study, + ) +} + +#let project_info(supervisor, consultant) = { + (supervisor: supervisor, consultant: consultant) +} + +#let abstract_info(abstract, keywords) = { + (content: abstract, keywords: keywords) +} diff --git a/template/classic/bp.typ b/template/classic/bp.typ index 23f5995..70e2054 100644 --- a/template/classic/bp.typ +++ b/template/classic/bp.typ @@ -13,62 +13,53 @@ bibliogr ) #import "../attachments.typ": attachment_list -#import "../utils.typ": is_none, assert_dict_has, assert_not_none, assert_type_signature +#import "../utils.typ": is_none, assert_dict_has, assert_not_none, assert_type_signature, map_none +#import "../arguments.typ": req_arg, get_arg, map_arg +#import "../theme.typ": faculty_color -#let bp( - // general settings - faculty_id, faculty_color, language, assignment_document, citation_file, - - // document info - title, author, author_pronouns, supervisor, consultant, study_programme, study_specialization, - year_of_study, abstract_content, acknowledgement_content, keywords, - - content -) = { +#let bp(args, content) = { let force_langs = ("cs", "en"); - assert_not_none(title, "title"); + + let title = req_arg(args, "title"); + let abstract_content = req_arg(args, "abstract.content"); + let keywords = req_arg(args, "abstract.keywords"); + let title_pages = get_arg(args, "title_pages"); + let language = req_arg(args, "document.language"); + assert_dict_has(force_langs, title, "title"); - - assert_not_none(study_programme, "study programme"); - assert_dict_has((language,), study_programme, "study programme"); - assert_not_none(study_specialization, "study specialization"); - assert_dict_has((language,), study_specialization, "study specialization"); - - assert_not_none(abstract_content, "abstract"); assert_dict_has(force_langs, abstract_content, "abstract"); if not is_none(keywords) { assert_dict_has(force_langs, keywords, "keywords"); } - if language == "cs" { - assert_not_none(author_pronouns, "author gender"); + + if is_none(title_pages) { + let programme = req_arg(args, "author.programme"); + assert_dict_has((language,), programme, "study programme"); + let specialization = req_arg(args, "author.specialization"); + assert_dict_has((language,), specialization, "study specialization"); + if language == "cs" { + let _ = req_arg(args, "author.pronouns"); + } } - assert_type_signature(supervisor, "string | none", "supervisor"); - assert_type_signature(consultant, "string | none", "consultant"); - - mainpage( - faculty_id, language, "bp", title, author, supervisor, consultant, study_programme, - study_specialization, year_of_study, - ); - assignment(language, assignment_document); - default_styling(false, faculty_color, { - disclaimer(language, faculty_id, "bp", author, author_pronouns); - if language == "cs" { - abstract("cs", title, abstract_content, keywords); - abstract("en", title, abstract_content, keywords); + if is_none(title_pages) { + mainpage(args); + assignment(args); + } + default_styling(false, faculty_color(req_arg(args, "document.faculty")), { + if is_none(title_pages) { + disclaimer(args); } - if language == "en" { - abstract("en", title, abstract_content, keywords); - abstract("cs", title, abstract_content, keywords); - } - acknowledgement(language, author, acknowledgement_content); + abstract("cs", args); + abstract("en", args); + acknowledgement(args); toc(language); tablelist(language); imagelist(language); abbrlist(language); pagebreak(weak: true); content; - bibliogr(language, citation_file); + bibliogr(args); attachment_list(language); }, language); } diff --git a/template/classic/classic.typ b/template/classic/classic.typ index d39d66d..429035e 100644 --- a/template/classic/classic.typ +++ b/template/classic/classic.typ @@ -2,52 +2,35 @@ #import "../theme.typ": faculty_logotype, tul_logomark, faculty_color #import "../lang.typ": lang_id, get_lang_item #import "../utils.typ": assert_in_dict, assert_in_arr, map_none, assert_dict_has +#import "../arguments.typ": req_arg, map_arg +#import "common.typ": default_styling // thesis types #import "bp.typ": bp #import "dp.typ": dp #import "other.typ": other -#let template_classic( - // general settings - language, faculty_id, document_type, citation_file, assignment_document, +#let template_classic(args, content) = { + let language = req_arg(args, "document.language"); - // document info - title, author, author_pronouns, supervisor, consultant, study_programme, study_specialization, - year_of_study, abstract, acknowledgement, keywords, - - // content - content, -) = { // argument pre-checking let document_types = ( "bp": bp, "dp": dp, "other": other, ) - assert_in_dict(document_type, document_types, "document type"); - map_none(title, (v) => assert_dict_has((language,), v, "title")); - map_none(study_programme, (v) => assert_dict_has((language,), v, "study programme")); - map_none(study_specialization, (v) => assert_dict_has((language,), v, "study specialization")); - map_none(acknowledgement, (v) => assert_dict_has((language,), v, "acknowledgement content")); - - document_types.at(document_type)( - faculty_id, - faculty_color(faculty_id), - language, - map_none(assignment_document, (v) => "../../" + v), - map_none(citation_file, (v) => "../../" + v), - title, - author, - author_pronouns, - supervisor, - consultant, - study_programme, - study_specialization, - year_of_study, - abstract, - acknowledgement, - keywords, - content, + assert_in_dict(req_arg(args, "document.type"), document_types, "document type"); + map_arg(args, "title", (v) => assert_dict_has((language,), v, "title")); + map_arg(args, "author.programme", (v) => assert_dict_has((language,), v, "study programme")); + map_arg( + args, "author.specialization", (v) => assert_dict_has((language,), v, "study specialization") ); + map_arg( + args, "acknowledgement", (v) => assert_dict_has((language,), v, "acknowledgement content") + ); + + args.assignment = map_arg(args, "assignment", (v) => "../../" + v); + args.citations = map_arg(args, "citations", (v) => "../../" + v); + + document_types.at(req_arg(args, "document.type"))(args, content); } diff --git a/template/classic/common.typ b/template/classic/common.typ index a09c7e2..3a5342f 100644 --- a/template/classic/common.typ +++ b/template/classic/common.typ @@ -1,6 +1,7 @@ #import "../theme.typ": faculty_logotype, tul_logomark, faculty_color #import "../lang.typ": get_lang_item, set_czech_nonbreakable_terms -#import "../utils.typ": is_none, assert_dict_has, map_none +#import "../utils.typ": is_none, assert_dict_has, has_all_none, map_none +#import "../arguments.typ": req_arg, get_arg #let base_font = "Inter"; #let mono_font = "Noto Sans Mono"; @@ -145,7 +146,7 @@ let gutter = .7em; // document type - if type(document_type) != type(none) { + if document_type != "other" { text(get_lang_item(language, document_type), weight: "bold", font: base_font); v(0em); } @@ -196,24 +197,32 @@ // MAINPAGE -#let mainpage( - faculty_id, - language, - document_type, - title, author, supervisor, consultant, study_programme, study_specialization, year_of_study, -) = { - import "../utils.typ": has_all_none, map_none - let nonetype = type(none); +#let mainpage(args) = { + let ( + language, document_type, faculty, + title, author, supervisor, consultant, study_programme, study_specialization, year_of_study, + ) = get_arg(args, ( + "document.language", + "document.type", + "document.faculty", + "title", + "author.name", + "project.supervisor", + "project.consultant", + "author.programme", + "author.specialization", + "author.year_of_study", + )); page({ if has_all_none(( document_type, title, author, supervisor, consultant, study_programme, )) { place(center + horizon, align(left, faculty_logotype(faculty_id, language))); } else { - header(faculty_id, language); + header(faculty, language); align({ info( - faculty_id, language, document_type, map_none(title, (v) => v.at(language)), + faculty, language, document_type, map_none(title, (v) => v.at(language)), author, supervisor, consultant, map_none(study_programme, (v) => v.at(language)), map_none(study_specialization, (v) => v.at(language)), year_of_study, ); @@ -225,11 +234,11 @@ // ASSIGNMENT PAGE -#let assignment(language, document) = { - if type(document) == type(none) { +#let assignment(args) = { + if is_none(get_arg(args, "assignment")) { page( place(center + horizon, text( - get_lang_item(language, "place_assignment"), + get_lang_item(req_arg(args, "document.language"), "place_assignment"), fill: red, size: 3em, font: base_font, @@ -247,8 +256,15 @@ // DISCLAIMER PAGE -#let disclaimer(language, faculty_id, disclaimer_type, author, author_pronouns) = { +#let disclaimer(args) = { import "../lang.typ": disclaimer + let (language, faculty, disclaimer_type, author, author_pronouns) = req_arg(args, ( + "document.language", + "document.faculty", + "document.type", + "author.name", + "author.pronouns", + )); heading(get_lang_item(language, "disclaimer"), numbering: none, outlined: false); par( text(disclaimer(language, disclaimer_type, author_pronouns)) @@ -266,7 +282,9 @@ // ACKNOWLEDGEMENT PAGE -#let acknowledgement(language, author, content) = { +#let acknowledgement(args) = { + let content = get_arg(args, "acknowledgement"); + let (language, author) = req_arg(args, ("document.language", "author.name")); if is_none(content) { return; } @@ -278,8 +296,10 @@ // ABSTRACT -#let abstract(language, title, content, keywords) = { - heading(text(title.at(language), font: base_font), numbering: none, outlined: false); +#let abstract(language, args) = { + heading( + text(req_arg(args, "title").at(language), font: base_font), numbering: none, outlined: false + ); v(2em); heading( level: 2, @@ -287,7 +307,8 @@ numbering: none, outlined: false, ); - text(content.at(language)); + text(req_arg(args, "abstract.content").at(language)); + let keywords = get_arg(args, "abstract.keywords"); if not is_none(keywords) and type(keywords.at(language)) != type(none) { linebreak(); linebreak(); @@ -387,7 +408,8 @@ // BIBLIOGRAPHY -#let bibliogr(language, citations_file) = { +#let bibliogr(args) = { + let (language, citations_file) = req_arg(args, ("document.language", "citations")); if language == "cs" { bibliography( citations_file, style: "../tul_citace.csl", title: get_lang_item(language, "bibliography"), diff --git a/template/classic/dp.typ b/template/classic/dp.typ index b3d6903..f0fe9ba 100644 --- a/template/classic/dp.typ +++ b/template/classic/dp.typ @@ -14,54 +14,53 @@ ) #import "../attachments.typ": attachment_list #import "../utils.typ": is_none, assert_dict_has, assert_not_none, assert_type_signature, map_none +#import "../arguments.typ": req_arg, get_arg, map_arg +#import "../theme.typ": faculty_color -#let dp( - // general settings - faculty_id, faculty_color, language, assignment_document, citation_file, - - // document info - title, author, author_pronouns, supervisor, consultant, study_programme, study_specialization, - year_of_study, abstract_content, acknowledgement_content, keywords, - - content -) = { +#let dp(args, content) = { let force_langs = ("cs", "en"); - assert_not_none(title, "title"); + + let title = req_arg(args, "title"); + let abstract_content = req_arg(args, "abstract.content"); + let keywords = req_arg(args, "abstract.keywords"); + let title_pages = get_arg(args, "title_pages"); + let language = req_arg(args, "document.language"); + assert_dict_has(force_langs, title, "title"); - - assert_not_none(study_programme, "study programme"); - assert_dict_has((language,), study_programme, "study programme"); - map_none(study_specialization, (v) => assert_dict_has((language,), v, "study specialization")); - - assert_not_none(abstract_content, "abstract"); assert_dict_has(force_langs, abstract_content, "abstract"); if not is_none(keywords) { assert_dict_has(force_langs, keywords, "keywords"); } - if language == "cs" { - assert_not_none(author_pronouns, "author gender"); + + if is_none(title_pages) { + let programme = req_arg(args, "author.programme"); + assert_dict_has((language,), programme, "study programme"); + let _ = map_arg( + args, "author.specialization", (v) => assert_dict_has((language,), v, "study specialization") + ); + if language == "cs" { + let _ = req_arg(args, "author.pronouns"); + } } - assert_type_signature(supervisor, "string | none", "supervisor"); - assert_type_signature(consultant, "string | none", "consultant"); - - mainpage( - faculty_id, language, "dp", title, author, supervisor, consultant, study_programme, - study_specialization, year_of_study, - ); - assignment(language, assignment_document); - default_styling(false, faculty_color, { - disclaimer(language, faculty_id, "dp", author, author_pronouns); - abstract("cs", title, abstract_content, keywords); - abstract("en", title, abstract_content, keywords); - acknowledgement(language, author, acknowledgement_content); + if is_none(title_pages) { + mainpage(args); + assignment(args); + } + default_styling(false, faculty_color(req_arg(args, "document.faculty")), { + if is_none(title_pages) { + disclaimer(args); + } + abstract("cs", args); + abstract("en", args); + acknowledgement(args); toc(language); tablelist(language); imagelist(language); abbrlist(language); pagebreak(weak: true); content; - bibliogr(language, citation_file); + bibliogr(args); attachment_list(language); - }); + }, language); } diff --git a/template/classic/other.typ b/template/classic/other.typ index ebfb3dc..30d4923 100644 --- a/template/classic/other.typ +++ b/template/classic/other.typ @@ -13,32 +13,22 @@ ) #import "../attachments.typ": attachment_list #import "../utils.typ": is_none, assert_not_none, assert_dict_has, assert_in_arr +#import "../arguments.typ": req_arg +#import "../theme.typ": faculty_color -#let other( - // general settings - faculty_id, faculty_color, language, assignment_document, citation_file, - - // document info - title, author, _, supervisor, consultant, study_programme, study_specialization, year_of_study, - abstract_content, _, keywords, - - content -) = { - assert_not_none(title, "title"); +#let other(args, content) = { + let (language, title) = req_arg(args, ("document.language", "title")); assert_dict_has((language,), title, "title"); - mainpage( - faculty_id, language, none, title, author, supervisor, consultant, study_programme, - study_specialization, year_of_study, - ); - default_styling(true, faculty_color, { + mainpage(args); + default_styling(true, faculty_color(req_arg(args, "document.faculty")), { toc(language); tablelist(language); imagelist(language); abbrlist(language); pagebreak(to: "even", weak: true); content; - bibliogr(language, citation_file); + bibliogr(args); attachment_list(language); }, language); } diff --git a/template/template.typ b/template/template.typ index 2027a61..3e80b39 100644 --- a/template/template.typ +++ b/template/template.typ @@ -26,6 +26,7 @@ // - faculty (str): Factulty abbreviation. One of "fs", "ft", "fp", "ef", "fua", "fm", "fzs", "cxi". // - lang (str): Language code. This can be "cs" or "en". // - document (str): Type of document. This can be "bp" or "other". +// - title_pages (str): The title pages exported from STAG (supported for some document types) // - title (dictionary): The title of the document. // - author (str): The name of the document's author. // - author_pronouns (str): The gender of the document's author. Needed only for the `cs` language. @@ -45,6 +46,7 @@ style: "classic", faculty: "tul", lang: "cs", document: "other", // document info + title_pages: none, title: none, keywords: none, abstract: none, acknowledgement: none, author: none, author_pronouns: none, supervisor: none, consultant: none, programme: none, specialization: none, year_of_study: none, @@ -55,38 +57,30 @@ // content content, ) = { - import "utils.typ": assert_in_dict, assert_type_signature + import "arguments.typ": ( + arguments, + document_info, + author_info, + project_info, + abstract_info, + check_arguments, + req_arg, + ) - // argument checking - assert_type_signature(style, "string", "visual style argument"); - assert_type_signature(faculty, "string", "faculty id argument"); - assert_type_signature(lang, "string", "language abbreviation argument"); - assert_type_signature(document, "string | none", "document kind argument"); - assert_type_signature(title, "dictionary[string : string] | none", "title argument"); - assert_type_signature(keywords, "dictionary[string : array[string]] | none", "keywords argument"); - assert_type_signature( - abstract, "dictionary[string : string | content] | none", "abstract argument" + let args = arguments( + document_info(style, faculty, lang, document), + title_pages, + title, + author_info(author, author_pronouns, programme, specialization, year_of_study), + project_info(supervisor, consultant), + abstract_info(abstract, keywords), + acknowledgement, + assignment, + citations, ); - assert_type_signature( - acknowledgement, "dictionary[string : string | content] | none", "acknowledgement content" - ); - assert_type_signature(author, "string | none", "author argument"); - assert_type_signature(author_pronouns, "string | none", "author gender argument"); - assert_type_signature( - supervisor, "string | dictionary[string : string] | none", "supervisor argument" - ); - assert_type_signature( - consultant, "string | dictionary[string : string] | none", "consultant argument" - ); - assert_type_signature( - programme, "dictionary[string : string] | none", "study programme argument" - ); - assert_type_signature( - specialization, "dictionary[string : string] | none", "study specialization argument" - ); - assert_type_signature(year_of_study, "integer | none", "year of study"); - assert_type_signature(assignment, "string | none", "assignment document argument"); - assert_type_signature(citations, "string", "citations file argument"); + check_arguments(args); + + import "utils.typ": assert_in_dict, assert_type_signature // templates import "classic/classic.typ": template_classic @@ -101,11 +95,7 @@ set text(lang: lang); // template call - templates.at(style)( - lang, faculty, document, citations, assignment, - title, author, author_pronouns, supervisor, consultant, - programme, specialization, year_of_study, abstract, acknowledgement, keywords, content - ); + templates.at(style)(args, content); import "prototyping.typ": assert_release_ready assert_release_ready(); diff --git a/template/utils.typ b/template/utils.typ index 26cc8c1..f6e4f2b 100644 --- a/template/utils.typ +++ b/template/utils.typ @@ -309,3 +309,11 @@ } mapper(value) } + +#let deref(arr) = { + if arr.len() == 0 { + arr.at(0) + } else { + arr + } +}