refactor: backport changes from noatu's fork

feat(style)!: remove reference styling & fix figure numbering for appendices
feat!: swap appending on 'none' being the first position in ..sink
feat: add chapters to pz-lb()
feat: add asserts
fix: better control flow

img() function now requires `none` to be the first position in ..sink,
e.g. `#img("/fig/1.png", "Caption", none)` to get "Caption (рисунок виконано самостійно)" caption.

Use `@some_label[див. рис.]` to get a "див. рис. 42" link.

Signed-off-by: unexplrd <unexplrd@linerds.us>
This commit is contained in:
2025-07-09 15:21:40 +03:00
parent d338c21965
commit 2e65baae70
3 changed files with 98 additions and 133 deletions

View File

@ -75,7 +75,7 @@ Some text
// If you ever need appendices in pz-lb template use the show rule // If you ever need appendices in pz-lb template use the show rule
// WARNING: when using coursework template use its own argument, // WARNING: when using coursework template use its own argument,
// so it can put bibliography before appendices // so it can put bibliography before appendices
#show: appendices_style #show: appendices-style
= Quote = Quote
#link("https://youtu.be/bJQj1uKtnus")[ #link("https://youtu.be/bJQj1uKtnus")[

227
lib.typ
View File

@ -66,9 +66,9 @@
}.replace(" ", "_") }.replace(" ", "_")
let caption = if sink.pos().len() == 0 { let caption = if sink.pos().len() == 0 {
caption + " (рисунок виконано самостійно)"
} else if sink.pos().first() == none {
caption caption
} else if sink.pos().first() == none {
caption + " (рисунок виконано самостійно)"
} else { } else {
[#caption (за даними #sink.pos().first())] [#caption (за даними #sink.pos().first())]
} }
@ -79,55 +79,62 @@
) #label(label_string)] ) #label(label_string)]
} }
// Styling {{{1 #let spacing = 0.95em // spacing between lines
/// NOTE: may be wrong #let num-to-alpha = "абвгдежиклмнпрстуфхцшщюя".split("") // 0 = "", 1 = "а"
#let ua_alpha_numbering = "абвгдежиклмнпрстуфхцшщюя".split("") // 0 = "", 1 = "а"
// general outlook {{{2 /// DSTU 3008:2015 Style
// spacing between lines /// -> content
#let spacing = 0.95em /// - it (content): Content to apply the style to.
/// - skip (int): Do not show page number for this number of pages.
// main {{{2 /// - offset (int): Adjust all page numbers by this amount.
#let style(it) = { #let dstu-style(
it,
skip: 0,
offset: 0,
) = {
// General Styling {{{1
set page( set page(
paper: "a4", paper: "a4",
margin: (top: 20mm, right: 10mm, bottom: 20mm, left: 25mm),
number-align: top + right, number-align: top + right,
numbering: (..numbers) => { margin: (top: 20mm, right: 10mm, bottom: 20mm, left: 25mm),
if numbers.pos().at(0) != 1 { numbering: (i, ..) => if i > skip { numbering("1", i + offset) },
numbering("1", numbers.pos().at(0))
}
},
) )
set text( set text(
font: ("Times New Roman", "Liberation Serif"), lang: "uk",
size: 14pt, size: 14pt,
hyphenate: false, hyphenate: false,
lang: "uk", font: ("Times New Roman", "Liberation Serif"),
) )
set par(justify: true, first-line-indent: (amount: 1.25cm, all: true))
set par(
justify: true,
spacing: spacing,
leading: spacing,
first-line-indent: (amount: 1.25cm, all: true),
)
set block(spacing: spacing)
set underline(evade: false) set underline(evade: false)
// set 1.5 line spacing // Enums & Lists {{{1
set block(spacing: spacing) // First level
set par(spacing: spacing)
set par(leading: spacing)
// enums and lists {{{3
set enum( set enum(
numbering: i => { ua_alpha_numbering.at(i) + ")" },
indent: 1.25cm, indent: 1.25cm,
body-indent: 0.5cm, body-indent: 0.5cm,
numbering: i => { num-to-alpha.at(i) + ")" },
) )
// Second level and further nesting
show enum: it => { show enum: it => {
set enum(indent: 0em, numbering: "1)") set enum(indent: 0em, numbering: "1)")
it it
} }
// Lists are not intended for multiple levels, use `enum`
set list(indent: 1.35cm, body-indent: 0.5cm, marker: [--]) set list(indent: 1.35cm, body-indent: 0.5cm, marker: [--])
// figures {{{3 // Figures {{{1
show figure: it => { show figure: it => {
v(spacing * 2, weak: true) v(spacing * 2, weak: true)
it it
@ -138,103 +145,52 @@
show figure.where(kind: table): set figure.caption(position: top) show figure.where(kind: table): set figure.caption(position: top)
show figure.caption.where(kind: table): set align(left) show figure.caption.where(kind: table): set align(left)
// figure numbering // Numbering {{{1
show heading.where(level: 1): it => { show heading.where(level: 1): it => {
counter(math.equation).update(0) counter(math.equation).update(0)
counter(figure.where(kind: raw)).update(0)
counter(figure.where(kind: image)).update(0) counter(figure.where(kind: image)).update(0)
counter(figure.where(kind: table)).update(0) counter(figure.where(kind: table)).update(0)
counter(figure.where(kind: raw)).update(0)
it it
} }
set math.equation( set figure(numbering: i => numbering("1.1", counter(heading).get().at(0), i))
numbering: (..num) => numbering( set math.equation(numbering: i => numbering(
"(1.1)", "(1.1)",
counter(heading).get().at(0), counter(heading).get().at(0),
num.pos().first(), i,
), ))
)
set figure(
numbering: (..num) => numbering(
"1.1",
counter(heading).get().at(0),
num.pos().first(),
),
)
// appearance of references to images and tables {{{3 // Headings {{{1
set ref(
supplement: it => {
if it == none or not it.has("kind") {
it
} else if it.kind == image {
"див. рис."
} else if it.kind == table {
"див. таблицю"
} else {
it
}
},
)
show ref: it => {
let el = it.element
if el == none or not el.has("kind") {
return it
}
if el.kind != image and el.kind != table {
return it
}
[(#it)]
}
// headings {{{3
set heading(numbering: "1.1") set heading(numbering: "1.1")
show heading.where(level: 1): it => { show heading: it => if it.level == 1 {
set align(center) set align(center)
set text(size: 14pt, weight: "semibold") set text(size: 14pt, weight: "semibold")
pagebreak(weak: true) pagebreak(weak: true)
upper(it) upper(it)
v(spacing * 2, weak: true) v(spacing * 2, weak: true)
} } else {
show heading.where(level: 2): it => {
set text(size: 14pt, weight: "regular") set text(size: 14pt, weight: "regular")
v(spacing * 2, weak: true) v(spacing * 2, weak: true)
block(width: 100%, spacing: 0em)[ block(width: 100%, spacing: 0em)[
#h(1.25cm) #h(1.25cm)
#counter(heading).display(it.numbering) #counter(heading).display(auto)
#it.body #it.body
] ]
v(spacing * 2, weak: true) v(spacing * 2, weak: true)
} }
show heading.where(level: 3): it => { // Listings {{{1
set text(size: 14pt, weight: "regular")
v(spacing * 2, weak: true)
block(width: 100%, spacing: 0em)[
#h(1.25cm)
#counter(heading).display(it.numbering)
#it.body
]
v(spacing * 2, weak: true)
}
// listings {{{3
show raw: it => { show raw: it => {
let new_spacing = 0.5em let raw-spacing = 0.5em
set block(spacing: new_spacing) set block(spacing: raw-spacing)
set par( set par(spacing: raw-spacing, leading: raw-spacing)
spacing: new_spacing,
leading: new_spacing,
)
set text( set text(
size: 11pt, size: 11pt,
font: ("Courier New", "Liberation Mono"),
weight: "semibold", weight: "semibold",
font: ("Courier New", "Liberation Mono"),
) )
v(spacing * 2.5, weak: true) v(spacing * 2.5, weak: true)
@ -243,46 +199,46 @@
} }
it it
// }}}
} }
// appendices {{{2 /// DSTU 3008:2015 Appendices Style
#let appendices_style(it) = { /// -> content
/// - it (content): Content to apply the style to.
#let appendices-style(it) = /* {{{ */ {
// Numbering
counter(heading).update(0) counter(heading).update(0)
set heading(numbering: (i, ..n) => (
upper(num-to-alpha.at(i)) + numbering(".1.1", ..n)
))
set figure(numbering: i => [#upper(num-to-alpha.at(counter(heading).get().at(0))).#i])
set math.equation(numbering: i => [(#upper(num-to-alpha.at(counter(heading).get().at(0))).#i)])
set heading( // Headings
numbering: (i, ..nums) => { show heading: it => if it.level == 1 {
let char = upper(ua_alpha_numbering.at(i))
if nums.pos().len() == 0 { char } else {
char + "." + nums.pos().map(str).join(".")
}
},
)
show heading.where(level: 1): it => {
set align(center) set align(center)
set text(size: 14pt, weight: "regular") set text(size: 14pt, weight: "regular")
pagebreak(weak: true) pagebreak(weak: true)
bold[ДОДАТОК #counter(heading).display(it.numbering)] text(weight: "bold")[ДОДАТОК #counter(heading).display(auto)]
linebreak() linebreak()
it.body it.body
v(spacing * 2, weak: true) v(spacing * 2, weak: true)
} } else {
show heading.where(level: 2): it => {
set text(size: 14pt, weight: "regular") set text(size: 14pt, weight: "regular")
v(spacing * 2, weak: true) v(spacing * 2, weak: true)
block(width: 100%, spacing: 0em)[ block(width: 100%, spacing: 0em)[
#h(1.25cm) #h(1.25cm)
#counter(heading).display(it.numbering) #counter(heading).display(auto)
#it.body #it.body
] ]
v(spacing * 2, weak: true) v(spacing * 2, weak: true)
} }
it it
} } // }}}
// Coursework template {{{1 // Coursework template {{{1
@ -315,7 +271,7 @@
) = { ) = {
set document(title: title, author: author.name) set document(title: title, author: author.name)
show: style show: dstu-style.with(skip: 1)
let bib-count = state("citation-counter", ()) let bib-count = state("citation-counter", ())
show cite: it => { show cite: it => {
@ -421,9 +377,7 @@
grid( grid(
columns: (1fr, 1fr, 1fr), columns: (1fr, 1fr, 1fr),
gutter: 0.3fr, gutter: 0.3fr,
[#bold[Курс] #uline(author.course)], [#bold[Курс] #uline(author.course)], [#bold[Група] #uline([#edu_program\-#author.group])], [#bold[Семестр] #uline(author.semester)],
[#bold[Група] #uline([#edu_program\-#author.group])],
[#bold[Семестр] #uline(author.semester)],
) )
linebreak() linebreak()
@ -640,7 +594,7 @@
} }
} }
appendices_style(appendices) appendices-style(appendices)
} }
// Practice and Laboratory works template {{{1 // Practice and Laboratory works template {{{1
@ -648,27 +602,33 @@
/// DSTU 3008:2015 Template for NURE /// DSTU 3008:2015 Template for NURE
/// -> content /// -> content
/// - doc (content): Content to apply the template to. /// - doc (content): Content to apply the template to.
/// - doctype ("ЛБ" | "ПЗ"): Document type.
/// - edu_program (str): Education program shorthand. /// - edu_program (str): Education program shorthand.
/// - title (str): Title of the document. /// - doctype ("ЛБ" | "ПЗ" | str): Document type.
/// - title (str or none): Title of the document. Optional.
/// - subject (str): Subject shorthand. /// - subject (str): Subject shorthand.
/// - authors ((name: str, full_name_gen: str, group: str, gender: str, variant: int or none),): List of authors.
/// - mentors ((name: str, degree: str, gender: str or none),): List of mentors.
/// - worknumber (int or none): Number of the work. Optional. /// - worknumber (int or none): Number of the work. Optional.
/// - authors ((name: str, full_name_gen: str, group: str, gender: str, variant: int or none),): List of authors.
/// - mentors ((name: str, degree: str, gender: str or none),): List of mentors. Optional.
/// - chapters (): List of file names in chapters/ subdirectory. Optional.
#let pz-lb( #let pz-lb(
doc, doc,
doctype: none,
university: "ХНУРЕ", university: "ХНУРЕ",
edu_program: none, edu_program: none,
doctype: none,
title: none, title: none,
subject: none, subject: none,
worknumber: none, worknumber: none,
authors: (), authors: (),
mentors: (), mentors: (),
chapters: (),
) = { ) = {
assert.ne(edu_program, none, message: "Missing argument: \"edu_program\"")
assert.ne(doctype, none, message: "Missing argument: \"doctype\"")
assert.ne(subject, none, message: "Missing argument: \"subject\"")
set document(title: title, author: authors.at(0).name) set document(title: title, author: authors.at(0).name)
show: style show: dstu-style.with(skip: 1)
let uni = universities.at(university) let uni = universities.at(university)
let edu_prog = uni.edu_programs.at(edu_program) let edu_prog = uni.edu_programs.at(edu_program)
@ -681,15 +641,19 @@
Кафедра #edu_prog.department_gen Кафедра #edu_prog.department_gen
\ \ \ \ \ \
Звіт \ #if doctype == "ЛБ" [Звіт \ з лабораторної роботи] else if (
з doctype == "ПЗ"
#if doctype == "ЛБ" [лабораторної роботи] else [практичної роботи] ) [Звіт \ з практичної роботи] else [#doctype]
#if worknumber != none { #if worknumber != none {
context counter(heading).update(worknumber - if title == none {0} else {1}) context counter(heading).update(
worknumber - if title == none { 0 } else { 1 },
)
[№#worknumber] [№#worknumber]
} else if title != none and worknumber != none {
context counter(heading).update(1)
} }
з дисципліни: "#uni.subjects.at(subject, default: "UNKNOWN SUBJECT, PLEASE OPEN AN ISSUE")" з дисципліни: "#uni.subjects.at(subject)"
#if title != none [з теми: "#title"] #if title != none [з теми: "#title"]
@ -708,7 +672,7 @@
if ( if (
"variant" in author.keys() and author.variant != none "variant" in author.keys() and author.variant != none
) [Варіант: #author.variant] ) [Варіант: #author.variant]
} else [ } else if authors.len() > 1 [
Виконали:\ Виконали:\
ст. гр. #edu_program\-#authors.at(0).group\ ст. гр. #edu_program\-#authors.at(0).group\
#for author in authors [#author.name\ ] #for author in authors [#author.name\ ]
@ -751,6 +715,7 @@
if title != none [#heading(title)] if title != none [#heading(title)]
doc doc
chapters.map(chapter => include "/chapters/" + str(chapter) + ".typ").join()
} }
// vim:sts=2:sw=2:fdl=0:fdm=marker:cms=/*%s*/ // vim:sts=2:sw=2:fdl=0:fdm=marker:cms=/*%s*/

View File

@ -30,7 +30,7 @@
- #lorem(42); - #lorem(42);
- #lorem(27). - #lorem(27).
#show: appendices_style #show: appendices-style
= Quote = Quote
#link("https://youtu.be/bJQj1uKtnus")[ #link("https://youtu.be/bJQj1uKtnus")[