Skip to content

Instantly share code, notes, and snippets.

@zr-tex8r
Last active May 6, 2024 09:08
Show Gist options
  • Save zr-tex8r/444ba5e27b3deff157b4ed7f62a0fe1a to your computer and use it in GitHub Desktop.
Save zr-tex8r/444ba5e27b3deff157b4ed7f62a0fe1a to your computer and use it in GitHub Desktop.
bxbibwrite:Typstで文献リストを直書きするやつ

bxbibwrite

Typst:文献リストを直書きするやつ

基本的な使い方

全項目importの形でパッケージを読み込む。

#import "@local/bxbibwrite:0.1.0": *

その直後に以下のshow ruleを設定する。

#show: use-bib-item-ref

文献リストはbibliography-list関数で出力できる。

#bibliography-list[
#bib-item(«ラベル1»)[«文献1»]
#bib-item(«ラベル2»)[«文献2»]
//...以下同様
]

ここで«文献n»には“実際に出力したいテキスト”を通常のTypstのマークアップで記述する。«ラベルn»には当該の文献項目に紐づけるラベル(label値)を指定する。

#bibliography-list[
#bib-item(<great>)[なんかすごい論文, 2000.]
]

文書中で文献参照番号(“[1]”等)を出力したい場合は、Typstの本来の文献リスト(bibliography()関数)での参照と同様に、文献に紐づくラベルに対する参照(ref関数)を記述する。

すごい論文 @great によると、……

@greatは単純に文献番号“[1]”を出力するだけで、その前後について何か“和文用の調整”をするわけではない。もし欧文空白を入れたくないなら、何か工夫をする必要がある(一般の@...記法の使用と同様)。

// 後ろになにも出力しない要素 #[] を挿入する.
すごい論文@great#[]によると、……
// #ref(<great>) や #[@great] でもよい

Typst本来の文献リスト項目への参照と同様に、supplementの引数は“補足説明”として“[1, 説明]”のような形式で出力される。

すごい本@great-book[3章]によると、……
// "[1, 3章]"と出力される

機能説明

  • use-bib-item-ref(«本体»)(function): 文書中で文献参照が正常に機能するようにする。つまり、本パッケージの文献参照の機能を利用したいならば以下のshow ruleを設定する必要がある。

    #show: use-bib-item-ref
    // 文献番号の書式を変えたいなら次のようにする
    #show: use-bib-item-ref.with(numbering: "(1)")
    • «本体»(content): 適用対象となる内容。前述のshow ruleの形で呼び出す場合は“以降の文章全部”となる。

    オプション引数:

    • numbering(str | function; 既定値"[1]"): 文献番号の書式。Typstのカウンタ書式と類似のパターン文字列または関数を指定する(詳細は後述)。
  • bibliography-list(«本体»)(function): 文献リストを出力する。
    ※1つの文書内で複数回使用できる。

    • «本体»(content): 文献リストの内容。

    オプション引数:

    • title(str | content; 既定値"Bibliography"): 文献リストの節見出しの内容。
    • heading-level(int | none; 既定値1): 節見出しの見出しレベル。noneを設定すると節見出しが出力されなくなる。
    • numbering(str | function | auto; 既定値auto): 文献リスト中の文献番号の書式。パターン文字列または関数で指定する。autoを指定すると、use-bib-item-refで指定した書式と同じになる。
      ※文献番号の書式を本文中の参照と文献リスト内で異なるものにしたい場合にこの引数を利用する。
    • key-width(length | auto; 既定値auto): 文献番号部分に確保される横幅。autoを指定すると、実際に出力した文献番号の横幅の最大値になる。
    • spacing(length | auto; 既定値auto): 文献項目の間の垂直空き。autoを設定すると、Typst本来の文献リストに合わせる。
    • body-indent(length; 既定値0.65em): 文献番号部分と本体の間の水平空き。
  • bib-item([«ラベル», ] «本体»)(function): 文献リストの項目を出力する。bibliography-list«本体»中でのみ使用できる。
    ※それ以外の場所で使用した場合の仕様は未定義である。逆に、bibliography-list«本体»中でbib-item以外のテキストを記述することは許容される。

    • «ラベル»(label | none; 既定値none): 文献項目に紐づくラベルを指定する。noneを指定した場合、項目は出力されるがそれを参照することはできない。
      ※記述の便宜のため位置引数であるが省略可能にしている。
    • «本体»(content): 文献項目の内容。要するにenumの本体と同じ扱いで、記述したものがそのまま出力される。

    オプション引数:

    • key(str | content | none; 既定値none): 文献番号を指定する。noneを指定した場合は自動採番される。
      ※“文献番号”を番号ではなく“[Knu20]”の類の形式にしたい場合はこの引数を用いる。

文献番号の書式設定

use-bib-item-refbibliography-listの両関数のnumbering引数には文献番号書式を指定する。これはTypstのカウンタ書式(numbering関数の第1引数)と同様にパターン文字列(pattern string)か関数かの何れかの値を指定できるが、カウンタ書式のものとは仕様が少し異なる。

パターン文字列について

文献番号のカウンタ値は常に単一値となるため、パターン文字列中のカウンタ記号(counting symbol)は最初に出現したもののみが有効になり、それ以降の文字列は全て接尾辞と見なされる。例えばパターンが(A/a)でありカウンタ値が4の場合の出力は“(D/a)”となる。

また、bib-item関数のkey引数で文献番号を直接指定した場合は、カウンタ記号の部分がkeyの値で置き換えられる。先の(A/a)の例で、key"Foo"を指定した場合の出力は“(Foo/a)”となる。

参照(ref関数)でsupplement引数が指定された場合は、“カウンタ記号の置換部分”にその内容が追記される。例えばsupplementに"Sup"を指定すると、出力は“(D, Sup/a)”や“(Foo, Sup/a)”のようになる。
※現状では“, ”の部分は固定である。

関数について

文献番号書式として関数を指定することもできる。この場合、関数は以下の仕様に従う必要がある。

  • 第1引数には“番号の本体部分”が渡される。これはkey引数を指定した場合はその値(strまたはcontent)、指定しない場合はカウンタ値(int)である。
  • 第2引数にはsupplement引数(str、content、noneの何れか)が渡される。supplement引数が指定されない場合はnoneになる。
  • 関数が返すべき値は文献番号の表現(strまたはcontent)である。

Typst本来の文献参照との相違点

文献に対する参照(ref関数)の挙動は本来のTypstの文献リストの項目に対するものと可能な限り合わせているが、以下のような相違点がある。

  • Typst本来の文献項目の参照はcite関数でも行えるが、本パッケージの文献項目の参照にはref関数(またはその簡易記法の@ラベル名)で行う必要がある。
  • Typst本来の文献項目の参照をrefで行った場合、refciteの両方の設定(show ruleなど)が適用される。本パッケージの文献項目の参照にはrefの設定のみが適用される。
  • Typst本来の文献項目の参照を複数並べた場合(@ref1 @ref2など)は間に自動的に“, ”が挿入される。本パッケージの文献項目の参照にはこの機能はない。
#import "@local/bxbibwrite:0.2.0": *
#show: use-bib-item-ref // 参照したい
#set page(paper: "a5")
#set text(
lang: "ja",
font: ("Linux Libertine", "Harano Aji Mincho"),
top-edge: 0.88em,
spacing: 0.25em,
)
= テスト
_Molecular Cell Biology_~@mcb-en(日本語訳は『分子細胞生物学』@mcb-ja)は_Molecular Biology of the Cell_~@mboc-en と並んで、しばしば分子生物学の入門書として読まれる本です。
#bibliography-list(
title: "参考文献", // 既定値は"Bibliography"
)[
#bib-item(<mcb-en>)[J. E. Darnell, D. Baltimore, H. Lodish, et al. _MOLECULAR CELL BIOLOGY, Fourth Edition._ W. H. Freeman, 2000.]
#bib-item(<mcb-ja>)[ボルティモア,ロディッシュ,ダーネル ほか(野田春彦,丸山工作 訳).『分子細胞生物学 第4版』.東京化学同人,2001年9月10日.]
#bib-item(<mboc-en>)[B. Alberts, D. Bray, J. Lewis, et al. _MOLECULAR BIOLOGY OF THE CELL, Fourth Edition._ Garland, 2002.]
]
#import "@local/bxbibwrite:0.2.0": *
#show: use-bib-item-ref.with(numbering: "☃1") // 番号の書式を指定
#set page(paper: "a5")
#set text(
lang: "ja",
font: ("Linux Libertine", "Harano Aji Mincho"),
top-edge: 0.88em,
spacing: 0.25em,
)
= テスト
_Molecular Cell Biology_~@mcb-en(日本語訳は『分子細胞生物学』@mcb-ja)は_Molecular Biology of the Cell_~@mboc-en と並んで、しばしば分子生物学の入門書として読まれる本です。
#bibliography-list(
title: "参考文献",
)[
#bib-item(<mcb-en>)[J. E. Darnell, D. Baltimore, H. Lodish, et al. _MOLECULAR CELL BIOLOGY, Fourth Edition._ W. H. Freeman, 2000.]
#bib-item(<mcb-ja>, key: "1J")[ボルティモア,ロディッシュ,ダーネル ほか(野田春彦,丸山工作 訳).『分子細胞生物学 第4版』.東京化学同人,2001年9月10日.] // 番号を変更
#bib-item(<mboc-en>)[B. Alberts, D. Bray, J. Lewis, et al. _MOLECULAR BIOLOGY OF THE CELL, Fourth Edition._ Garland, 2002.]
#bib-item[某ZR.マクロツイーター.インタァーネット.] // ラベルなし
]
#let (
bibliography-list,
bib-item,
use-bib-item-ref,
) = {
let title-default = "Bibliography"
let numbering-default = "[1]"
let figure-kind = "bx-bib-item"
let end-mark = <bx-bib-end>
let bib-counter = counter(figure.where(kind: figure-kind))
let max-key-width = state("bx-max-key-width", 0pt)
let get-numbering(list-num, fig-num) = {
// When the numbering for listing is given, it is used.
// Otherwise the figure.numbering is applied,
// but adjust it if it is at default.
if list-num != auto { list-num }
else if fig-num == "1" { "[1]" }
else { fig-num }
}
let get-auto-key-width() = {
let marks = query(selector(end-mark).after(here()))
if marks.len() == 0 { return max-key-width.final() }
max-key-width.at(marks.first().location())
}
// Makes the key string.
let format-key(num, count, key, supplement) = {
// If key is not given, count should be shown.
let val = if key != none { key } else { count }
// Delegate if numbering is a function.
if type(num) == function {
return num(val, supplement)
}
// Parse the pattern.
let pos = none
let cs = num.codepoints()
let pos = cs.position(c => {
c in "1aAiI" or not ("2" in numbering(c + "1", 2, 1))
})
if pos == none { return num } // abnormal
// Replace the counter symbol with the real value.
if type(val) == int {
val = numbering(cs.at(pos), val)
}
if supplement != none {
val = { val; ", "; supplement }
}
cs.at(pos) = val
cs.join("")
}
// Prints the bibliography list.
let bibliography-list(
title: title-default,
heading-level: 1,
numbering: auto,
key-width: auto,
body-indent: 0.65em,
spacing: auto,
adjust-spacing: auto,
body,
) = {
let use-adjuster = (
if adjust-spacing != auto { adjust-spacing == true }
else { spacing == auto }
)
// Print the heading.
if heading-level != none {
let head = heading(level: heading-level, numbering: none, title)
if use-adjuster {
block(below: 0pt, head)
} else {
head
}
}
// The figure (i.e. bib-item) is laid out here.
show figure.where(kind: figure-kind): it => {
assert(it.body.func() == metadata)
let width = (
if key-width != auto { key-width }
else { get-auto-key-width() }
)
let count = it.counter.get().at(0)
let data = it.body.value
let numbering = get-numbering(numbering, it.numbering)
let key = format-key(numbering, count, data.key, none)
let kbox = box(width: width, {key; h(1fr)})
let entry = enum(
numbering: _ => kbox, // simply show the result
body-indent: body-indent,
tight: true,
enum.item(count, data.body),
)
if spacing == auto {
block(entry)
} else {
block(entry, above: spacing, below: spacing)
}
let metric = measure(key)
max-key-width.update(val => calc.max(val, metric.width))
}
if use-adjuster {
block(height: 0pt)
}
max-key-width.update(0pt)
body
[#metadata(none)#end-mark]
}
// The helper for bib-item.
let do-bib-item(key, label, body) = {
// Make a figure with the data.
let fig = figure(
kind: figure-kind,
supplement: key,
outlined: false,
metadata((
key: key,
body: body,
)),
)
// Then output with the label.
[#fig#label]
if key != none {
bib-counter.update(v => v - 1) // no increment
}
}
// A Bibliography entry.
let bib-item(
key: none,
..args, // [label,] body
) = {
args = args.pos()
assert(
args.len() >= 1,
message: "missing argument in 'bib-item': body",
)
assert(
args.len() <= 2,
message: "unexpected argument in 'bib-item'",
)
let (lbl, body) = if (args.len() == 1) {
(none,) + args
} else { args }
assert(
lbl == none or type(lbl) == label,
message: "'label' must be none or label, found " + str(type(lbl)),
)
do-bib-item(key, lbl, body)
}
let use-bib-item-ref(
numbering: numbering-default,
body,
) = {
show figure.where(kind: figure-kind): set figure(
numbering: numbering,
)
show ref: it => {
let el = it.element
if not (el != none and
el.func() == figure and el.kind == figure-kind) {
return it
}
let count = bib-counter.at(el.location()).at(0)
let sup = it.supplement
if sup == auto { sup = none }
format-key(el.numbering, count, el.supplement, sup)
}
body
}
( // export
bibliography-list,
bib-item,
use-bib-item-ref,
)
}
[package]
name = "bxbibwrite"
version = "0.2.0"
entrypoint = "bxbibwrite.typ"
compiler = "0.11.0"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment