-
Notifications
You must be signed in to change notification settings - Fork 0
/
style_base.typ
153 lines (143 loc) · 3.8 KB
/
style_base.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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#import "types.typ": *
#let _ex_style(name, elem, styler, pred) = {
let ex_style = (elem, makeup) => {
let style = if t_check(TMakeup, makeup) {
makeup.style
} else {
makeup
}
if type(style) == "string" {
panic(sytle)
}
if name != none and name in style {
styler(elem, style)
} else {
panic("missing '" + name + "' in style definition")
}
}
let precedence = makeup => {
let style = if t_check(TMakeup, makeup) {
makeup.style
} else {
makeup
}
if name != none and name in style {
pred(style)
} else {
panic("missing '" + name + "' in style definition")
}
}
let style = (fn: ex_style, precedence: precedence)
if t_check(TElem, elem) {
elem.styles.push(style)
elem
} else if type(elem) == "array" {
elem.flatten().map(e => if t_check(TElem, e) {
e.styles.push(style)
e
} else {
(value: e, styles: (style,))
})
} else {
(value: elem, styles: (style,))
}
}
#let _choose_styler(style, names, def_fmt, style_name) = {
let s = style
let style_stack = ()
for name in names {
if name in s {
s = s.at(name)
style_stack.push(s)
} else {
break
}
}
while style_stack.len() > 0 {
let style = style_stack.pop()
if style_name in style {
return style.at(style_name)
}
}
def_fmt
}
#let elem(value, ..names, style: none, style_name: "style") = _ex_style(
names.pos().at(0),
value,
(elem, _style) => {
let default_styler = if style != none { style } else { i=>repr(i) }
let styler = _choose_styler(_style, names.pos(), default_styler, style_name)
styler(elem)
},
style => _choose_styler(style, names.pos(), 0, "precedence")
)
#let eval_line(elem, makeup) = elem.flatten().map(e =>
if t_check(TElem, e) {
if e.styles.len() == 0 {
e.value
} else {
let first_style = e.styles.at(0)
let ex_prec = first_style.precedence
let acc = (fn: first_style.fn, prec: ex_prec(makeup))
let chosen_style = e.styles.slice(1).fold(acc, (acc, style_def) => {
let ex_precedence = style_def.precedence
let precedence = ex_precedence(makeup)
if precedence > acc.prec {
(fn: style_def.fn, prec: precedence)
} else {
acc
}
})
let styler = chosen_style.fn
if t_check(TGroupStart, e.value) {
(start_style: v => styler(v, makeup.style), ..e.value)
} else if t_check(TGroupEnd, e.value) {
(end_style: v => styler(v, makeup.style), ..e.value)
} else {
styler(e.value, makeup)
}
}
} else {
e
}
)
#let sp = " "
#let join(elems, sep) = if elems.len() == 0 {()} else if elems.len() == 1 { elems.at(0) } else { range(elems.len()*2-1).map(i => if calc.even(i) {elems.at(int(i/2))} else {sep}) }
#let ge = (value: (group: none), styles: ())
#let gs(fn, use_start: false, use_end: false) = (value: (group: fn, use_start: use_start, use_end: use_end), styles: ())
#let pipe(..fns) = s => {
let _s = s
for fn in fns.pos() {
let r = fn(_s)
// first element, if successful, second the value
if type(r) == "array" {
// if successful, stop otherwise continue
if r.at(0) {
return r.at(1)
}
} else {
_s = r
}
}
_s
}
#let _if(cond, ..fns) = s => {
if cond(s) {
let p = pipe(..fns)
p(s)
} else {
s
}
}
#let _if_else(cond, ..fns) = s => {
if cond(s) {
let p = pipe(..fns)
(true, p(s))
} else {
(false, none)
}
}
#let if_string(..fns) = _if(s => type(s) == "string", ..fns)
#let if_number(..fns) = _if(s => type(s) == "integer" or type(s) == "float", ..fns)
#let if_string_else(..fns) = _if_else(s => type(s) == "string", ..fns)
#let if_number_else(..fns) = _if_else(s => type(s) == "integer" or type(s) == "float", ..fns)