Skip to content

Commit

Permalink
add parse args sink example to docs
Browse files Browse the repository at this point in the history
  • Loading branch information
PgBiel committed Jan 13, 2025
1 parent a47df16 commit 00cc9b5
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 2 deletions.
35 changes: 34 additions & 1 deletion docs/book/src/elements/creating/overriding-constr.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,41 @@ You can use `construct: default-constructor => (..args) => value` to override th

## Custom argument parsing

You can use `parse-args: default-constructor => (args, include-required: bool) => dictionary with fields` to override the built-in argument parser. This is used both for the constructor and for set rules.
You can use `parse-args: (default arg parser, fields: dictionary, typecheck: bool) => (args, include-required: bool) => dictionary with fields` to override the built-in argument parser. This is used both for the constructor and for set rules.

Here, `args` is an [`arguments`](https://typst.app/docs/reference/foundations/arguments/) and `include-required: true` indicates the function is being called in the constructor, so **required fields must be parsed and enforced.**

However, `include-required: false` indicates a call in set rules, so **required fields must not be parsed and forbidden.**

### Argument sink

Here's how you'd use this to implement a positional argument sink:

```rs
#let sunk = e.element.declare(
"sunk",
display: it => {
(it.run)(it)
},
fields: (
field("values", e.types.array(stroke), required: true),
field("run", function, required: true, named: true),
field("color", color, default: red),
field("inner", content, default: [Hello!]),
),
parse-args: (default-parser, fields: none, typecheck: none) => (args, include-required: false) => {
let pos = args.pos()
let values = if include-required {
pos
} else {
assert(false, message: "element 'sunk': unexpected positional arguments\n hint: these can only be passed to the constructor")
}

default-parser(arguments(values, ..args.named()), include-required: include-required)
},
prefix: ""
)

// Use 'run: func' as an example to test and ensure we received the correct fields
#sunk(5pt, 10pt, black, 5pt + black, run: it => assert.eq(it.values, (5pt, 10pt, black, 5pt + black).map(stroke)))
```
31 changes: 30 additions & 1 deletion docs/book/src/types/custom-types/other-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,33 @@ If all of your fields may be omitted (for example), or if you just generally wan

Much like elements, you can use `construct: default-constructor => (..args) => value` to override the default constructor for your custom type. **You should use `construct:` rather than create a wrapper function** to ensure that [data retrieval functions](../../misc/reference/data.md), such as `e.data(func)`, still work.

You can use `parse-args: default-constructor => (args, include-required: true) => dictionary with fields` to override the built-in argument parser to the constructor (instead of overriding the entire constructor). `include-required` is always true and is simply a remnant from elements' own argument parser (which share code with the one used for custom types).
You can use `parse-args: (default arg parser, fields: dictionary, typecheck: bool) => (args, include-required: true) => dictionary with fields` to override the built-in argument parser to the constructor (instead of overriding the entire constructor). `include-required` is always true and is simply a remnant from elements' own argument parser (which share code with the one used for custom types).

### Argument sink

Here's how you'd use this to implement a positional argument sink:

```rs
#let sunk = e.types.declare(
"sunk",
fields: (
field("values", e.types.array(stroke), required: true),
field("color", color, default: red),
field("inner", content, default: [Hello!]),
),
parse-args: (default-parser, fields: none, typecheck: none) => (args, include-required: true) => {
let pos = args.pos()
let values = if include-required {
pos
} else {
// include-required is always true for types, but keep this here just for completeness
assert(false, message: "type 'sunk': unexpected positional arguments\n hint: these can only be passed to the constructor")
}

default-parser(arguments(values, ..args.named()), include-required: include-required)
},
prefix: ""
)

#assert.eq(e.fields(sunk(5pt, black, 5pt + black, inner: [A])), (values: (stroke(5pt), stroke(black), 5pt + black), inner: [A], color: red))
```

0 comments on commit 00cc9b5

Please sign in to comment.