213 lines
7.4 KiB
Typst
213 lines
7.4 KiB
Typst
#import "@preview/alexandria:0.2.2": alexandria, get-bibliography, load-bibliography
|
||
|
||
// Global state
|
||
#let used-refs = state("used-refs", ())
|
||
|
||
// 1. Analizes and sets up the document
|
||
#let bib-setup(body) = {
|
||
show: alexandria(prefix: "cite:", read: path => read(path))
|
||
|
||
// Searching for references in document
|
||
show ref: it => {
|
||
let target = str(it.target)
|
||
if target.starts-with("cite:") {
|
||
let key = target.slice(5)
|
||
used-refs.update(arr => if key not in arr { arr + (key,) } else { arr })
|
||
context {
|
||
let cites = used-refs.final()
|
||
let bib = get-bibliography("cite:")
|
||
let get-type(k) = {
|
||
let e = bib.references.find(x => x.key == k)
|
||
if e != none { lower(e.details.at("type", default: "")) } else { "" }
|
||
}
|
||
let is-book(t) = t == "book"
|
||
let is-article(t) = t == "article" or t == "paper-conference" or t == "inproceedings"
|
||
let is-other(t) = not is-book(t) and not is-article(t)
|
||
|
||
let books = cites.filter(k => is-book(get-type(k)))
|
||
let articles = cites.filter(k => is-article(get-type(k)))
|
||
let others = cites.filter(k => is-other(get-type(k)))
|
||
|
||
let sorted = books + articles + others
|
||
let idx = sorted.position(k => k == key)
|
||
|
||
if idx != none { link(it.target, [\[#(idx + 1)\]]) } else { [\[?\]] }
|
||
}
|
||
} else { it }
|
||
}
|
||
|
||
body
|
||
}
|
||
|
||
// 2. Bibliography rendering
|
||
#let render-bib() = {
|
||
load-bibliography("Bibliography.bib", prefix: "cite:", full: true, style: "ieee")
|
||
|
||
heading(level: 1, outlined: false)[Spis literatury]
|
||
v(1em)
|
||
|
||
context {
|
||
let cites = used-refs.final()
|
||
if cites.len() > 0 {
|
||
let bib = get-bibliography("cite:")
|
||
let get-entry(k) = bib.references.find(e => e.key == k)
|
||
|
||
// custom implementation adapting the ZUT's formatting
|
||
let format-custom(entry) = {
|
||
let d = entry.details
|
||
let entry-type = lower(d.at("type", default: ""))
|
||
|
||
let format-author(a) = {
|
||
if type(a) == dictionary {
|
||
let parts = ()
|
||
if "given" in a { parts.push(str(a.given)) }
|
||
if "family" in a { parts.push(str(a.family)) }
|
||
if parts.len() > 0 { return parts.join(" ") }
|
||
if "name" in a { return str(a.name) }
|
||
return ""
|
||
} else {
|
||
let s = str(a)
|
||
let parts = s.split(",")
|
||
if parts.len() == 2 { return parts.at(1).trim() + " " + parts.at(0).trim() }
|
||
return s
|
||
}
|
||
}
|
||
|
||
let raw-auth = d.at("author", default: ())
|
||
let author-list = if type(raw-auth) == array {
|
||
raw-auth.map(format-author)
|
||
} else if raw-auth != none and raw-auth != "" {
|
||
(format-author(raw-auth),)
|
||
} else { () }
|
||
|
||
let authors = if author-list.len() > 1 {
|
||
author-list.slice(0, -1).join(", ") + " i " + author-list.last()
|
||
} else if author-list.len() == 1 { author-list.first() } else { "" }
|
||
|
||
let get-val(..keys) = {
|
||
let extract(obj, k) = {
|
||
if type(obj) != dictionary { return none }
|
||
let v = obj.at(k, default: none)
|
||
if v == none { return none }
|
||
if type(v) == str { return v }
|
||
if type(v) in (int, float) { return str(v) }
|
||
if type(v) == array { return v.filter(x => type(x) in (str, int, float)).map(x => str(x)).join(", ") }
|
||
if type(v) == dictionary {
|
||
if "isbn" in v { return str(v.isbn) }
|
||
if "value" in v { return str(v.value) }
|
||
if "name" in v { return str(v.name) }
|
||
if "text" in v { return str(v.text) }
|
||
return ""
|
||
}
|
||
return ""
|
||
}
|
||
for k in keys.pos() {
|
||
let res = extract(d, k)
|
||
if res == none and "parent" in d { res = extract(d.parent, k) }
|
||
if res != none and res != "" { return res }
|
||
}
|
||
return ""
|
||
}
|
||
|
||
let y = ""
|
||
let m = ""
|
||
let date-val = d.at("date", default: none)
|
||
if type(date-val) == dictionary {
|
||
y = str(date-val.at("year", default: ""))
|
||
m = str(date-val.at("month", default: ""))
|
||
} else if date-val != none { y = str(date-val) }
|
||
if y == "" { y = get-val("year") }
|
||
if m == "" { m = get-val("month") }
|
||
|
||
if m != "" {
|
||
if m.match(regex("^\d+$")) != none {
|
||
let idx = int(m)
|
||
let months = (
|
||
"",
|
||
"sty.",
|
||
"lut.",
|
||
"mar.",
|
||
"kwi.",
|
||
"maj",
|
||
"cze.",
|
||
"lip.",
|
||
"sie.",
|
||
"wrz.",
|
||
"paź.",
|
||
"lis.",
|
||
"gru.",
|
||
)
|
||
if idx >= 1 and idx <= 12 { m = months.at(idx) }
|
||
}
|
||
}
|
||
let year = if m != "" { m + y } else { y }
|
||
let title-txt = get-val("title")
|
||
let series = get-val("collection-title", "series")
|
||
let pub-place = get-val("location", "address", "publisher-place")
|
||
let pub = get-val("publisher")
|
||
let edition = get-val("edition")
|
||
let volume = get-val("volume")
|
||
let pages = get-val("page-range", "pages").replace("--", "–").replace("-", "–")
|
||
let isbn = get-val("isbn", "ISBN", "serial-number", "number")
|
||
let issue = get-val("issue", "number")
|
||
let url = get-val("url")
|
||
|
||
if entry-type == "book" [
|
||
#authors. #emph(title-txt).
|
||
#if edition != "" { if edition.match(regex("^\d+$")) != none [#edition wyd. ] else [#edition. ] }
|
||
#if volume != "" [T. #volume. ]
|
||
#if series != "" [#series. ]
|
||
#if pub-place != "" [#pub-place: ]
|
||
#if pub != "" [#pub, ]
|
||
#year#if pages != "" [, s. #pages].
|
||
#if isbn != "" [ isbn: #isbn.]
|
||
] else if entry-type == "article" or entry-type == "paper-conference" [
|
||
#authors. „#title-txt”. W:#if volume != "" or issue != "" [ #volume#if issue != "" [.#issue]] (#year)#if pages != "" [, s. #pages].
|
||
] else [
|
||
#authors. #emph(title-txt).
|
||
#if url != "" [ URL: #link(url)[#raw(url)].]
|
||
]
|
||
}
|
||
|
||
let get-type(k) = {
|
||
let e = get-entry(k)
|
||
if e != none { lower(e.details.at("type", default: "")) } else { "" }
|
||
}
|
||
|
||
let is-book(t) = t == "book"
|
||
let is-article(t) = t == "article" or t == "paper-conference" or t == "inproceedings"
|
||
let is-other(t) = not is-book(t) and not is-article(t)
|
||
|
||
let render-group(title, keys, start-idx) = {
|
||
if keys.len() > 0 [
|
||
#heading(level: 2, title, outlined: false)
|
||
#grid(
|
||
columns: (auto, 1fr),
|
||
column-gutter: 0.65em,
|
||
row-gutter: 1em,
|
||
..keys
|
||
.enumerate()
|
||
.map(((i, k)) => {
|
||
let entry = get-entry(k)
|
||
if entry == none { return () }
|
||
let num = start-idx + i + 1
|
||
([\[#num\]], [#format-custom(entry)#label("cite:" + k)])
|
||
})
|
||
.flatten()
|
||
)
|
||
#v(1em)
|
||
]
|
||
}
|
||
|
||
let books = cites.filter(k => is-book(get-type(k)))
|
||
let articles = cites.filter(k => is-article(get-type(k)))
|
||
let others = cites.filter(k => is-other(get-type(k)))
|
||
|
||
// last parameter is start idx
|
||
render-group("Książki", books, 0)
|
||
render-group("Artykuły", articles, books.len())
|
||
render-group("Źródła internetowe i inne", others, books.len() + articles.len())
|
||
}
|
||
}
|
||
}
|