Skip to content

Commit 4481a29

Browse files
committed
Introduce new syntax for explicit block type
This introduce a new, more explicit labels `block-type=...` which is meant to replace the four separate labels `cram`, `ocaml`, `toplevel` and `include` in the future. It is added for a transition period at the end of which the four labels of the apocalypse should be removed in favor of this new one. Signed-off-by: Nathan Rebours <[email protected]>
1 parent 5708b6e commit 4481a29

File tree

13 files changed

+166
-35
lines changed

13 files changed

+166
-35
lines changed

CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
#### Added
44

5+
- Add alternative syntax for explicitly setting the block-type.
6+
The new label `block-type=...` can be set to `ocaml`, `toplevel`, `cram` or
7+
`include`. (#<PR_NUMBER>, @NathanReb)
8+
59
#### Changed
610

711
#### Deprecated

lib/block.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ let infer_block ~config ~header ~contents ~errors =
384384

385385
let mk ~loc ~section ~labels ~legacy_labels ~header ~contents ~errors =
386386
let block_kind =
387-
get_label (function Block_kind x -> Some x | _ -> None) labels
387+
get_label (function Block_type x -> Some x | _ -> None) labels
388388
in
389389
let config = get_block_config labels in
390390
(match block_kind with

lib/label.ml

Lines changed: 56 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,13 @@ type non_det = Nd_output | Nd_command
7373

7474
let default_non_det = Nd_output
7575

76-
type block_kind = OCaml | Cram | Toplevel | Include
76+
type block_type = OCaml | Cram | Toplevel | Include
77+
78+
let pp_block_type ppf = function
79+
| OCaml -> Fmt.string ppf "ocaml"
80+
| Cram -> Fmt.string ppf "cram"
81+
| Toplevel -> Fmt.string ppf "toplevel"
82+
| Include -> Fmt.string ppf "include"
7783

7884
type t =
7985
| Dir of string
@@ -86,13 +92,7 @@ type t =
8692
| Version of Relation.t * Ocaml_version.t
8793
| Set of string * string
8894
| Unset of string
89-
| Block_kind of block_kind
90-
91-
let pp_block_kind ppf = function
92-
| OCaml -> Fmt.string ppf "ocaml"
93-
| Cram -> Fmt.string ppf "cram"
94-
| Toplevel -> Fmt.string ppf "toplevel"
95-
| Include -> Fmt.string ppf "include"
95+
| Block_type of block_type
9696

9797
let pp ppf = function
9898
| Dir d -> Fmt.pf ppf "dir=%s" d
@@ -108,7 +108,7 @@ let pp ppf = function
108108
Fmt.pf ppf "version%a%a" Relation.pp op Ocaml_version.pp v
109109
| Set (v, x) -> Fmt.pf ppf "set-%s=%s" v x
110110
| Unset x -> Fmt.pf ppf "unset-%s" x
111-
| Block_kind bk -> pp_block_kind ppf bk
111+
| Block_type bt -> Fmt.pf ppf "block-type=%a" pp_block_type bt
112112

113113
let is_prefix ~prefix s =
114114
let len_prefix = String.length prefix in
@@ -142,41 +142,67 @@ let requires_value ~label ~value f =
142142

143143
let requires_eq_value ~label ~value f =
144144
requires_value ~label ~value (fun op value ->
145-
match op with Relation.Eq -> Ok (f value) | _ -> non_eq_op ~label)
145+
match op with Relation.Eq -> (f value) | _ -> non_eq_op ~label)
146+
147+
let version_of_string s =
148+
match Ocaml_version.of_string s with
149+
| Ok v -> Ok v
150+
| Error (`Msg e) ->
151+
Util.Result.errorf "Invalid version: %s." e
152+
153+
let parse_non_det_value ~label s =
154+
match s with
155+
| "output" -> Ok Nd_output
156+
| "command" -> Ok Nd_command
157+
| s ->
158+
let allowed_values = [ "<none>"; {|"command"|}; {|"output"|} ] in
159+
invalid_value ~label ~allowed_values s
160+
161+
let parse_block_type_value ~label s =
162+
match s with
163+
| "ocaml" -> Ok OCaml
164+
| "cram" -> Ok Cram
165+
| "toplevel" -> Ok Toplevel
166+
| "include" -> Ok Include
167+
| s ->
168+
let allowed_values =
169+
[{|"ocaml"|}; {|"cram"|}; {|"toplevel"|}; {|"include"|}]
170+
in
171+
invalid_value ~label ~allowed_values s
146172

147173
let interpret label value =
174+
let open Util.Result.Infix in
148175
match label with
149176
| "skip" -> doesnt_accept_value ~label ~value Skip
150-
| "ocaml" -> doesnt_accept_value ~label ~value (Block_kind OCaml)
151-
| "cram" -> doesnt_accept_value ~label ~value (Block_kind Cram)
152-
| "toplevel" -> doesnt_accept_value ~label ~value (Block_kind Toplevel)
153-
| "include" -> doesnt_accept_value ~label ~value (Block_kind Include)
177+
| "ocaml" -> doesnt_accept_value ~label ~value (Block_type OCaml)
178+
| "cram" -> doesnt_accept_value ~label ~value (Block_type Cram)
179+
| "toplevel" -> doesnt_accept_value ~label ~value (Block_type Toplevel)
180+
| "include" -> doesnt_accept_value ~label ~value (Block_type Include)
154181
| v when is_prefix ~prefix:"unset-" v ->
155182
doesnt_accept_value ~label ~value
156183
(Unset (split_prefix ~prefix:"unset-" v))
157184
| "version" ->
158-
requires_value ~label ~value (fun op v ->
159-
match Ocaml_version.of_string v with
160-
| Ok v -> Ok (Version (op, v))
161-
| Error (`Msg e) ->
162-
Util.Result.errorf "Invalid `version` label value: %s." e)
185+
requires_value ~label ~value
186+
(fun op v -> version_of_string v >>= fun v -> Ok (Version (op, v)))
163187
| "non-deterministic" -> (
164188
match value with
165189
| None -> Ok (Non_det None)
166-
| Some (Relation.Eq, "output") -> Ok (Non_det (Some Nd_output))
167-
| Some (Relation.Eq, "command") -> Ok (Non_det (Some Nd_command))
168-
| Some (Relation.Eq, v) ->
169-
let allowed_values = [ "<none>"; {|"command"|}; {|"output"|} ] in
170-
invalid_value ~label ~allowed_values v
190+
| Some (Relation.Eq, s) ->
191+
parse_non_det_value ~label s >>= fun nd ->
192+
Ok (Non_det (Some nd))
171193
| Some _ -> non_eq_op ~label)
172-
| "dir" -> requires_eq_value ~label ~value (fun x -> Dir x)
173-
| "source-tree" -> requires_eq_value ~label ~value (fun x -> Source_tree x)
174-
| "file" -> requires_eq_value ~label ~value (fun x -> File x)
175-
| "part" -> requires_eq_value ~label ~value (fun x -> Part x)
176-
| "env" -> requires_eq_value ~label ~value (fun x -> Env x)
194+
| "dir" -> requires_eq_value ~label ~value (fun x -> Ok (Dir x))
195+
| "source-tree" ->
196+
requires_eq_value ~label ~value (fun x -> Ok (Source_tree x))
197+
| "file" -> requires_eq_value ~label ~value (fun x -> Ok (File x))
198+
| "part" -> requires_eq_value ~label ~value (fun x -> Ok (Part x))
199+
| "env" -> requires_eq_value ~label ~value (fun x -> Ok (Env x))
200+
| "block-type" ->
201+
requires_eq_value ~label ~value
202+
(fun x -> parse_block_type_value ~label x >>= fun bt -> Ok (Block_type bt))
177203
| l when is_prefix ~prefix:"set-" l ->
178204
requires_eq_value ~label ~value (fun x ->
179-
Set (split_prefix ~prefix:"set-" l, x))
205+
Ok (Set (split_prefix ~prefix:"set-" l, x)))
180206
| l -> Error (`Msg (Format.sprintf "`%s` is not a valid label." l))
181207

182208
let of_string s =

lib/label.mli

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ type non_det = Nd_output | Nd_command
2929

3030
val default_non_det : non_det
3131

32-
type block_kind = OCaml | Cram | Toplevel | Include
32+
type block_type = OCaml | Cram | Toplevel | Include
3333

3434
type t =
3535
| Dir of string
@@ -42,7 +42,7 @@ type t =
4242
| Version of Relation.t * Ocaml_version.t
4343
| Set of string * string
4444
| Unset of string
45-
| Block_kind of block_kind
45+
| Block_type of block_type
4646

4747
val pp : Format.formatter -> t -> unit
4848

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
It is possible to explicitly state the type of a block using the
2+
`block-type` label, working around language header and content based
3+
inference which can sometime lead to troublesome error messages.
4+
5+
The following blocks use a volontarily misleading language header that would
6+
normally lead to errors if we let MDX infer the type of block based on them.
7+
8+
```sh block-type=toplevel
9+
# 1 + 1;;
10+
```
11+
12+
```sh block-type=ocaml
13+
let x = 2
14+
```
15+
16+
```ocaml block-type=cram
17+
$ echo "boom"
18+
```
19+
20+
The include block type is somewhat redundant with the `file=...` label as
21+
so it is not tested here.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
It is possible to explicitly state the type of a block using the
2+
`block-type` label, working around language header and content based
3+
inference which can sometime lead to troublesome error messages.
4+
5+
The following blocks use a volontarily misleading language header that would
6+
normally lead to errors if we let MDX infer the type of block based on them.
7+
8+
```ocaml block-type=toplevel
9+
# 1 + 1;;
10+
- : int = 2
11+
```
12+
13+
```ocaml block-type=ocaml
14+
let x = 2
15+
```
16+
17+
```sh block-type=cram
18+
$ echo "boom"
19+
boom
20+
```
21+
22+
The include block type is somewhat redundant with the `file=...` label as
23+
so it is not tested here.

test/bin/mdx-test/expect/dune.inc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@
1111
(alias runtest)
1212
(action (diff bash-fence/test-case.md.expected bash-fence.actual)))
1313

14+
(rule
15+
(target block-type.actual)
16+
(deps (package mdx) (source_tree block-type))
17+
(action
18+
(with-stdout-to %{target}
19+
(chdir block-type
20+
(run ocaml-mdx test --output - test-case.md)))))
21+
22+
(rule
23+
(alias runtest)
24+
(action (diff block-type/test-case.md.expected block-type.actual)))
25+
1426
(rule
1527
(target casual-file-inc.actual)
1628
(deps (package mdx) (source_tree casual-file-inc))
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
This tests that erros are properly reported when the `block-type` label
2+
is misused.
3+
4+
It requires a value
5+
6+
```ocaml block-type
7+
```
8+
9+
It only accept a fixed set of values
10+
11+
```ocaml block-type=invalid
12+
```
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[mdx] Fatal error: File "test-case.md", line 6: invalid code block: Label `block-type` requires a value.

test/bin/mdx-test/failure/dune.inc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,17 @@
11

2+
(rule
3+
(target block-type-value.actual)
4+
(deps (package mdx) (source_tree block-type-value))
5+
(action
6+
(with-accepted-exit-codes 1
7+
(with-outputs-to %{target}
8+
(chdir block-type-value
9+
(run %{bin:ocaml-mdx} test test-case.md))))))
10+
11+
(rule
12+
(alias runtest)
13+
(action (diff block-type-value/test-case.md.expected block-type-value.actual)))
14+
215
(rule
316
(target both-prelude.actual)
417
(deps (package mdx) (source_tree both-prelude))
@@ -52,6 +65,19 @@
5265
(enabled_if (<> %{os_type} Win32))
5366
(action (diff in-toplevel/test-case.md.expected in-toplevel.actual)))
5467

68+
(rule
69+
(target include-without-file-label.actual)
70+
(deps (package mdx) (source_tree include-without-file-label))
71+
(action
72+
(with-accepted-exit-codes 1
73+
(with-outputs-to %{target}
74+
(chdir include-without-file-label
75+
(run %{bin:ocaml-mdx} test test-case.md))))))
76+
77+
(rule
78+
(alias runtest)
79+
(action (diff include-without-file-label/test-case.md.expected include-without-file-label.actual)))
80+
5581
(rule
5682
(target invalid-label.actual)
5783
(deps (package mdx) (source_tree invalid-label))

0 commit comments

Comments
 (0)