-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathruby.typ
93 lines (83 loc) · 2.93 KB
/
ruby.typ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#let _ruby(rt, rb, size, pos, dy, alignment, delimiter) = {
if not ("center", "start", "between", "around").contains(alignment) {
panic("'" + repr(alignment) + "' is not a valid ruby alignment")
}
if not (top, bottom).contains(pos) {
panic("pos can be either top or bottom but '"+ repr(pos) +"'")
}
let extract_content(content, fn: it => it) = {
let func = content.func()
return if func == text or func == raw {
(content.text, fn)
} else {
extract_content(content.body, fn: it => func(fn(it)))
}
}
let rb_array = if type(rb) == "content" {
let (inner, func) = extract_content(rb)
inner.split(delimiter).map(func)
} else if type(rb) == "string" {
rb.split(delimiter)
} else {(rb,)}
assert(type(rb_array) == "array")
let rt_array = rt.split(delimiter)
if rt_array.len() != rb_array.len() {
rt_array = (rt,)
rb_array = (rb,)
}
let gutter = if (alignment=="center" or alignment=="start") {
h(0pt)
} else if (alignment=="between" or alignment=="around") {
h(1fr)
}
box(style(st=> {
let sum_body = []
let sum_width = 0pt
let i = 0
while i < rb_array.len() {
let (body, ruby) = (rb_array.at(i), rt_array.at(i))
let bodysize = measure(body, st)
let rt_plain_width = measure(text(size: size, ruby), st).width
let width = if rt_plain_width > bodysize.width {rt_plain_width} else {bodysize.width}
let chars = if(alignment=="around") {
h(0.5fr) + ruby.clusters().join(gutter) + h(0.5fr)
} else {
ruby.clusters().join(gutter)
}
let rubytext = box(width: width, align(if(alignment=="start"){left}else{center}, text(size: size, chars)))
let textsize = measure(rubytext, st)
let dx = textsize.width - bodysize.width
let (t_dx, l_dx, r_dx) = if(alignment=="start"){(0pt, 0pt, dx)}else{(-dx/2, dx/2, dx/2)}
let (l, r) = (i != 0, i != rb_array.len() - 1)
sum_width += if l {0pt} else {t_dx}
let dy = if pos == top {-1.5 * textsize.height - dy} else {bodysize.height + textsize.height/2 + dy}
place(
top+left,
dx: sum_width,
dy: dy,
rubytext
)
sum_width += width
sum_body += if l {h(l_dx)} + body + if r {h(r_dx)}
i += 1
}
sum_body
}))
}
#let get_ruby(
size: .5em,
dy: 0pt,
pos: top,
alignment: "center",
delimiter: "|"
) = (rt, rb, alignment: alignment) => _ruby(rt, rb, size, pos, dy, alignment, delimiter)
#let test() = [
#set box(stroke: red+.001pt)
#set text(size: 50pt)
#show: align.with(center)
#let ruby = get_ruby(pos: bottom)
#ruby("した")[下]
#let ruby = get_ruby()
#ruby("うえ")[上]
]
//#test()