|
2 | 2 |
|
3 | 3 | // ==== internal utilities |
4 | 4 |
|
| 5 | +// https://github.com/jneug/typst-mantys/blob/cb32c63394ef441eb6038d4090634c7d823b9e11/src/api/types.typ |
| 6 | +/// Dictionary of builtin types, mapping the types name to its actual type. |
| 7 | +#let _type-map = ( |
| 8 | + "auto": auto, |
| 9 | + "none": none, |
| 10 | + // foundations |
| 11 | + arguments: arguments, |
| 12 | + array: array, |
| 13 | + bool: bool, |
| 14 | + bytes: bytes, |
| 15 | + content: content, |
| 16 | + datetime: datetime, |
| 17 | + decimal: decimal, |
| 18 | + dictionary: dictionary, |
| 19 | + duration: duration, |
| 20 | + float: float, |
| 21 | + function: function, |
| 22 | + int: int, |
| 23 | + label: label, |
| 24 | + module: module, |
| 25 | + regex: regex, |
| 26 | + selector: selector, |
| 27 | + string: str, |
| 28 | + symbol: symbol, |
| 29 | + type: type, |
| 30 | + version: version, |
| 31 | + // layout |
| 32 | + alignment: alignment, |
| 33 | + angle: angle, |
| 34 | + direction: direction, |
| 35 | + fraction: fraction, |
| 36 | + length: length, |
| 37 | + ratio: ratio, |
| 38 | + relative: relative, |
| 39 | + // visualize |
| 40 | + color: color, |
| 41 | + gradient: gradient, |
| 42 | + stroke: stroke, |
| 43 | + tiling: tiling, |
| 44 | + // introspection |
| 45 | + counter: counter, |
| 46 | + location: location, |
| 47 | + state: state, |
| 48 | +) |
| 49 | +/// Dictionary of allowed type aliases, like `dict` for `dictionary`. |
| 50 | +#let _type-aliases = ( |
| 51 | + boolean: "bool", |
| 52 | + str: "string", |
| 53 | + arr: "array", |
| 54 | + dict: "dictionary", |
| 55 | + integer: "int", |
| 56 | + func: "function", |
| 57 | +) |
| 58 | +#let _type-link-map = ( |
| 59 | + "auto": "foundations/auto", |
| 60 | + "none": "foundations/none", |
| 61 | + // foundation |
| 62 | + arguments: "foundations/arguments", |
| 63 | + array: "foundations/array", |
| 64 | + bool: "foundations/bool", |
| 65 | + bytes: "foundations/bytes", |
| 66 | + content: "foundations/content", |
| 67 | + datetime: "foundations/datetime", |
| 68 | + decimal: "foundations/decimal", |
| 69 | + dictionary: "foundations/dictionary", |
| 70 | + duration: "foundations/duration", |
| 71 | + float: "foundations/float", |
| 72 | + function: "foundations/function", |
| 73 | + integer: "foundations/int", |
| 74 | + label: "foundations/label", |
| 75 | + module: "foundations/module", |
| 76 | + regex: "foundations/regex", |
| 77 | + selector: "foundations/selector", |
| 78 | + string: "foundations/str", |
| 79 | + symbol: "foundations/symbol", |
| 80 | + type: "foundations/type", |
| 81 | + version: "foundations/version", |
| 82 | + // layout |
| 83 | + alignment: "layout/alignment", |
| 84 | + angle: "layout/angle", |
| 85 | + direction: "layout/direction", |
| 86 | + fraction: "layout/fraction", |
| 87 | + length: "layout/length", |
| 88 | + ratio: "layout/ratio", |
| 89 | + relative: "layout/relative", |
| 90 | + // visualize |
| 91 | + color: "visualize/color", |
| 92 | + gradient: "visualize/gradient", |
| 93 | + stroke: "visualize/stroke", |
| 94 | + tiling: "visualize/tiling", |
| 95 | + // introspection |
| 96 | + counter: "foundations/counter", |
| 97 | + location: "foundations/location", |
| 98 | + state: "foundations/state", |
| 99 | +) |
| 100 | +#let type-link(t, body) = { |
| 101 | + if t in _type-aliases { t = _type-aliases.at(t) } |
| 102 | + if t in _type-link-map { |
| 103 | + link("https://typst.app/docs/reference/" + _type-link-map.at(t), body) |
| 104 | + } else { |
| 105 | + // probably a custom type |
| 106 | + body |
| 107 | + } |
| 108 | +} |
| 109 | + |
| 110 | +#let serif-font = "Libertinus Serif" |
5 | 111 | #let mono = text.with(font: "DejaVu Sans Mono", size: 0.85em, weight: 340) |
6 | 112 | #let name-fill = rgb("#1f2a63") |
7 | 113 | #let signature-fill = rgb("#d8dbed") |
|
47 | 153 | stroke: (left: bar-width + name-fill), |
48 | 154 | outset: (left: -bar-width / 2), |
49 | 155 | inset: (x: 0.7em, y: 0.7em), |
| 156 | + sticky: true, |
50 | 157 | ..args |
51 | 158 | ) |
52 | 159 | } |
53 | 160 |
|
54 | | -#let preview-block(no-codly: true, ..args) = { |
| 161 | +#let preview-block(body, no-codly: true, in-raw: true, ..args) = { |
55 | 162 | import "template.typ": codly |
56 | 163 |
|
57 | 164 | show: if no-codly { codly.no-codly } else { it => it } |
| 165 | + set heading(numbering: none, outlined: false) |
| 166 | + // counteract the font changes of raw blocks |
| 167 | + set text(font: serif-font, size: 1em/0.96) if in-raw |
| 168 | + |
58 | 169 | block( |
| 170 | + pad(-2pt, body), |
59 | 171 | stroke: 0.5pt + luma(200), |
60 | 172 | radius: preview-radius, |
61 | 173 | ..args |
62 | 174 | ) |
63 | 175 | } |
64 | 176 |
|
| 177 | +#let layout-example(..args) = { |
| 178 | + import "template.typ": tidy, t4t |
| 179 | + import tidy.show-example as example |
| 180 | + |
| 181 | + example.default-layout-example( |
| 182 | + code-block: (body, ..args) => { |
| 183 | + // counteract the raw font size decrease of the template being applied twice |
| 184 | + set text(size: 1em/0.9) |
| 185 | + t4t.assert.no-pos(args) |
| 186 | + let args = args.named() |
| 187 | + _ = args.remove("inset", default: none) |
| 188 | + block(pad(x: -4.3%, body), ..args) |
| 189 | + }, |
| 190 | + preview-block: preview-block, |
| 191 | + ..args, |
| 192 | + ) |
| 193 | +} |
| 194 | + |
65 | 195 | // ==== functions required from styles |
66 | 196 |
|
67 | 197 | #let show-outline(module-doc, style-args: (:)) = { |
|
99 | 229 | // Create beautiful, colored type box |
100 | 230 | #let show-type(type, style-args: (:)) = { |
101 | 231 | h(2pt) |
102 | | - box(outset: 2pt, fill: get-type-color(type), radius: 2pt, raw(type, lang: none)) |
| 232 | + type-link(type, { |
| 233 | + box(outset: 2pt, fill: get-type-color(type), radius: 2pt, raw(type, lang: none)) |
| 234 | + }) |
103 | 235 | h(2pt) |
104 | 236 | } |
105 | 237 |
|
|
114 | 246 | let lbl = if style-args.enable-cross-references { |
115 | 247 | label(style-args.label-prefix + fn.name + "()") |
116 | 248 | } |
117 | | - [#parameter-list #lbl] |
| 249 | + [#parameter-list#lbl] |
118 | 250 | }) |
119 | 251 | pad(x: 0em, eval-docstring(fn.description, style-args)) |
120 | 252 |
|
|
133 | 265 | style-args, |
134 | 266 | show-default: "default" in info, |
135 | 267 | default: info.at("default", default: none), |
| 268 | + function-name: style-args.label-prefix + fn.name, |
136 | 269 | ) |
137 | 270 | }) |
138 | 271 |
|
139 | 272 | if args.len() != 0 { |
140 | | - [*#style-args.local-names.parameters:*] |
| 273 | + let parameters-string = get-local-name("parameters", style-args: style-args) |
| 274 | + [*#parameters-string:*] |
141 | 275 | args.join() |
142 | 276 | } |
143 | 277 | v(4em, weak: true) |
|
153 | 287 | args = args.filter(((arg-name, info)) => not arg-name.starts-with("_")) |
154 | 288 | } |
155 | 289 | args = args.map(((arg-name, info)) => { |
| 290 | + if style-args.enable-cross-references and not (info.at("description", default: "") == "" and style-args.omit-empty-param-descriptions) { |
| 291 | + arg-name = link(label(style-args.label-prefix + fn.name + "." + arg-name.trim(".")), arg-name) |
| 292 | + } |
156 | 293 | arg-name |
157 | 294 | if "types" in info [: #show-types(info.types, style-args)] |
158 | 295 | }) |
|
168 | 305 | name, types, content, style-args, |
169 | 306 | show-default: false, |
170 | 307 | default: none, |
| 308 | + function-name: none, |
171 | 309 | ) = block( |
172 | 310 | breakable: style-args.break-param-descriptions, |
173 | 311 | inset: 0pt, width: 100%, |
174 | 312 | { |
175 | 313 | set par(hanging-indent: 1em, first-line-indent: 0em) |
176 | | - mono(name) |
| 314 | + let lbl = if function-name != none and style-args.enable-cross-references { |
| 315 | + label(function-name + "." + name.trim(".")) |
| 316 | + } |
| 317 | + [#mono(name)#lbl] |
177 | 318 | [ (] |
178 | 319 | show-types(types, style-args, joiner: [ #text(size: 0.6em)[or] ]) |
179 | 320 | if show-default [ \= #raw(lang: "typc", default)] |
|
183 | 324 | ) |
184 | 325 |
|
185 | 326 | #let show-reference(label, name, style-args: none) = { |
186 | | - link(label, raw(name, lang: none)) |
| 327 | + let (name, args) = if name.ends-with("()") { |
| 328 | + (name.slice(0, -2), ()) |
| 329 | + } else { |
| 330 | + (name, none) |
| 331 | + } |
| 332 | + link(label, mono-fn(name, args: args)) |
187 | 333 | } |
188 | 334 |
|
189 | 335 | #let show-variable( |
|
207 | 353 | v(4em, weak: true) |
208 | 354 | } |
209 | 355 |
|
210 | | -// Adapted from https://github.com/Mc-Zen/tidy/blob/v0.3.0/src/show-example.typ |
211 | | -// see discussion here: https://discord.com/channels/1054443721975922748/1296208677371379813 |
212 | | - |
213 | | -/// Takes given code and both shows it and previews the result of its evaluation. |
214 | | -/// |
215 | | -/// The code is by default shown in the language mode `lang: typc` (typst code) |
216 | | -/// if no language has been specified. Code in typst markup language (`lang: typ`) |
217 | | -/// is automatically evaluated in markup mode. |
218 | | -/// |
219 | | -/// - code (raw): Raw object holding the example code. |
220 | | -/// - scope (dictionary): Additional definitions to make available for the evaluated |
221 | | -/// example code. |
222 | | -/// - scale-preview (auto, ratio): How much to rescale the preview. If set to auto, the the preview is scaled to fit the box. |
223 | | -/// - inherited-scope (dictionary): Definitions that are made available to the entire parsed |
224 | | -/// module. This parameter is only used internally. |
225 | | -#let show-example( |
226 | | - code, |
227 | | - dir: ltr, |
228 | | - scope: (:), |
229 | | - preamble: "", |
230 | | - ratio: 1, |
231 | | - scale-preview: auto, |
232 | | - mode: "code", |
233 | | - inherited-scope: (:), |
234 | | - code-block: block, |
235 | | - preview-block: preview-block, |
236 | | - col-spacing: 5pt, |
237 | | - ..options |
238 | | -) = { |
239 | | - set raw(block: true) |
240 | | - let lang = if code.has("lang") { code.lang } else { "typc" } |
241 | | - if lang == "typ" { |
242 | | - mode = "markup" |
243 | | - } |
244 | | - if mode == "markup" and not code.has("lang") { |
245 | | - lang = "typ" |
246 | | - } |
247 | | - set raw(lang: lang) |
248 | | - if code.has("block") and code.block == false { |
249 | | - code = raw(code.text, lang: lang, block: true) |
250 | | - } |
251 | | - |
252 | | - let preview = { |
253 | | - set heading(numbering: none, outlined: false) |
254 | | - [#eval(preamble + code.text, mode: mode, scope: scope + inherited-scope)] |
255 | | - } |
256 | | - |
257 | | - let preview-outer-padding = 3pt |
258 | | - let preview-inner-padding = 5pt |
259 | | - |
260 | | - show: if dir.axis() == "vertical" { pad.with(x: 4%) } else { it => it } |
261 | | - |
262 | | - layout(size => { |
263 | | - let code-width |
264 | | - let preview-width |
265 | | - |
266 | | - if dir.axis() == "vertical" { |
267 | | - code-width = size.width |
268 | | - preview-width = size.width |
269 | | - } else { |
270 | | - code-width = ratio / (ratio + 1) * size.width - 0.5 * col-spacing |
271 | | - preview-width = size.width - code-width - col-spacing |
272 | | - } |
273 | | - |
274 | | - let available-preview-width = preview-width - 2 * (preview-outer-padding + preview-inner-padding) |
275 | | - |
276 | | - let preview-size |
277 | | - let scale-preview = scale-preview |
278 | | - |
279 | | - if scale-preview == auto { |
280 | | - preview-size = measure(preview) |
281 | | - assert(preview-size.width != 0pt, message: "The code example has a relative width. Please set `scale-preview` to a fixed ratio, e.g., `100%`") |
282 | | - scale-preview = calc.min(1, available-preview-width / preview-size.width) * 100% |
283 | | - } else { |
284 | | - preview-size = measure(block(preview, width: available-preview-width / (scale-preview / 100%))) |
285 | | - } |
286 | | - |
287 | | - set par(hanging-indent: 0pt) // this messes up some stuff in case someone sets it |
288 | | - |
289 | | - |
290 | | - // We first measure this thing (code + preview) to find out which of the two has |
291 | | - // the larger height. Then we can just set the height for both boxes. |
292 | | - let arrangement(width: 100%, height: auto) = { |
293 | | - let code-block = code-block( |
294 | | - width: code-width, |
295 | | - height: height, |
296 | | - { |
297 | | - set text(size: .9em) |
298 | | - pad(x: -4.3%, code) |
299 | | - } |
300 | | - ) |
301 | | - let preview-block = preview-block( |
302 | | - height: height, |
303 | | - width: preview-width, |
304 | | - inset: preview-outer-padding, |
305 | | - box( |
306 | | - width: 100%, |
307 | | - fill: white, |
308 | | - inset: preview-inner-padding, |
309 | | - scale( |
310 | | - scale-preview, |
311 | | - origin: top + left, |
312 | | - block(preview, height: preview-size.height, width: preview-size.width) |
313 | | - ) |
314 | | - ) |
315 | | - ) |
316 | | - |
317 | | - show: block.with( |
318 | | - width: width, |
319 | | - inset: 0pt, |
320 | | - ) |
| 356 | +#let show-example(no-codly: true, in-raw: true, ..args) = { |
| 357 | + import "template.typ": tidy |
| 358 | + import tidy.show-example as example |
321 | 359 |
|
322 | | - grid( |
323 | | - ..if dir.axis() == "horizontal" { |
324 | | - (columns: 2, rows: 1, column-gutter: col-spacing) |
325 | | - } else { |
326 | | - (columns: 1, rows: 2, row-gutter: col-spacing) |
327 | | - }, |
328 | | - ..if dir in (ltr, ttb) { |
329 | | - (code-block, preview-block) |
330 | | - } else { |
331 | | - (preview-block, code-block) |
332 | | - } |
333 | | - ) |
334 | | - } |
335 | | - let height = if dir.axis() == "vertical" { auto } |
336 | | - else { measure(arrangement(width: size.width)).height } |
337 | | - arrangement(height: height) |
338 | | - }) |
| 360 | + example.show-example( |
| 361 | + layout: layout-example.with( |
| 362 | + preview-block: preview-block.with(no-codly: no-codly, in-raw: in-raw), |
| 363 | + ), |
| 364 | + ..args, |
| 365 | + ) |
339 | 366 | } |
0 commit comments