Skip to content

Commit 2ba5471

Browse files
authored
odoc: Don't add unecessary space in references and links (#2608)
Avoid adding a space before the text of a reference or link: {{!ref}text} {{:url}text} As regular comments might be formatted as docstrings, the space must be preserved if it appears in the source to avoid crashing. odoc-parser is changed to preserve this information. This slightly changes the formatting of references and links: {{:https://github.com/mirage/irmin/blob/main/README_PPX.md} documentation - for [ppx_irmin]})*) + for [ppx_irmin]})*) ... - of similar bindings themselves, by using the appropriate {{!Merge.MSet} - multi-sets}. *) + of similar bindings themselves, by using the appropriate + {{!Merge.MSet} multi-sets}. *)
1 parent 7ebe9fc commit 2ba5471

File tree

9 files changed

+62
-31
lines changed

9 files changed

+62
-31
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ profile. This started with version 0.26.0.
106106
- \* Fix arrow type indentation with `break-separators=before` (#2598, @Julow)
107107
- Fix missing parentheses around a let in class expressions (#2599, @Julow)
108108
- Fix formatting of paragraphs in lists in documentation (#2607, @Julow)
109+
- Avoid unwanted space in references and links text in documentation (#2608, @Julow)
109110

110111
## 0.26.2 (2024-04-18)
111112

lib/Fmt_odoc.ml

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ let str_normalized ?(escape = escape_all) c s =
8989
|> fun s -> list s space_break (fun s -> escape s |> str)
9090
else str (escape s)
9191

92+
let rec drop_leading_spaces = function
93+
| {Loc.value= `Space _; _} :: tl -> drop_leading_spaces tl
94+
| elems -> elems
95+
9296
let ign_loc ~f with_loc = f with_loc.Loc.value
9397

9498
let fmt_verbatim_block ~loc s =
@@ -204,18 +208,10 @@ let list_block_elem c elems f =
204208
in
205209
f elem $ break )
206210

207-
let space_elt c : inline_element with_location =
208-
let sp = if c.conf.fmt_opts.wrap_docstrings.v then "" else " " in
209-
Loc.(at (span []) (`Space sp))
210-
211211
let non_wrap_space sp =
212212
if String.contains sp '\n' then force_newline else str sp
213213

214214
let rec fmt_inline_elements c elements =
215-
let wrap_elements opn cls ~always_wrap hd = function
216-
| [] -> wrap_if always_wrap opn cls hd
217-
| tl -> wrap opn cls (hd $ fmt_inline_elements c (space_elt c :: tl))
218-
in
219215
let rec aux = function
220216
| [] -> noop
221217
| `Space sp :: `Word (("-" | "+") as w) :: t ->
@@ -252,20 +248,35 @@ let rec fmt_inline_elements c elements =
252248
in
253249
hovbox_if c.conf.fmt_opts.wrap_docstrings.v
254250
(1 + String.length s + 1)
255-
(wrap_elements (str "{") (str "}") ~always_wrap:true
251+
(fmt_markup_with_inline_elements c ~force_space:true
256252
(str_normalized c s) elems )
257253
$ aux t
258254
| `Reference (_kind, rf, txt) :: t ->
259-
let rf = wrap (str "{!") (str "}") (fmt_reference rf) in
260-
wrap_elements (str "{") (str "}") ~always_wrap:false rf txt $ aux t
255+
let rf = str "{!" $ fmt_reference rf $ str "}" in
256+
fmt_link_or_reference c rf txt $ aux t
261257
| `Link (url, txt) :: t ->
262-
let url = wrap (str "{:") (str "}") (str_normalized c url) in
263-
hovbox_if c.conf.fmt_opts.wrap_docstrings.v 2
264-
@@ wrap_elements (str "{") (str "}") ~always_wrap:false url txt
265-
$ aux t
258+
let url = str "{:" $ str_normalized c url $ str "}" in
259+
fmt_link_or_reference c url txt $ aux t
266260
in
267261
aux (List.map elements ~f:(ign_loc ~f:Fn.id))
268262

263+
and fmt_link_or_reference c tag txt =
264+
match txt with
265+
| [] -> tag
266+
| _ :: _ ->
267+
hovbox_if c.conf.fmt_opts.wrap_docstrings.v 1
268+
(fmt_markup_with_inline_elements c tag txt)
269+
270+
(** Format a markup of the form [{tag elems}]. If [force_space] is [true], a
271+
space will be added after the tag, even if it's not present in the source.
272+
*)
273+
and fmt_markup_with_inline_elements c ?(force_space = false) tag elems =
274+
let leading_space, elems =
275+
if force_space then (str " ", drop_leading_spaces elems)
276+
else (noop, elems)
277+
in
278+
str "{" $ tag $ leading_space $ fmt_inline_elements c elems $ str "}"
279+
269280
and fmt_nestable_block_element c elm =
270281
match elm.Loc.value with
271282
| `Paragraph elems -> hovbox 0 (fmt_inline_elements c elems)
@@ -348,12 +359,9 @@ let fmt_block_element c elm =
348359
| Some lbl -> str ":" $ str_normalized c lbl
349360
| None -> noop
350361
in
351-
let elems =
352-
if List.is_empty elems then elems else space_elt c :: elems
353-
in
362+
let tag = str lvl $ lbl in
354363
hovbox 0
355-
(wrap (str "{") (str "}")
356-
(str lvl $ lbl $ fmt_inline_elements c elems) )
364+
(fmt_markup_with_inline_elements c ~force_space:true tag elems)
357365
| #nestable_block_element as value ->
358366
hovbox 0 (fmt_nestable_block_element c {elm with value})
359367

test/passing/tests/doc.mld

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,6 @@ and we shall get
157157
]}
158158

159159
For more about [odoc] commands, simply invoke [odoc --help] in your shell.
160+
161+
Preserve the space between a link/reference and its text:
162+
{{:foo}bar} {{:foo} bar} {{!foo}bar} {{!foo} bar}

test/passing/tests/doc.mld.ref

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{0 Parent/Child Specification}
22
This parent/child specification allows more flexible output support, e.g.,
33
per library documentation. See
4-
{{:https://v3.ocaml.org/packages} v3.ocaml.org/packages}.
4+
{{:https://v3.ocaml.org/packages}v3.ocaml.org/packages}.
55

66
The rules are;
77

@@ -160,3 +160,6 @@ and we shall get
160160
]}
161161

162162
For more about [odoc] commands, simply invoke [odoc --help] in your shell.
163+
164+
Preserve the space between a link/reference and its text: {{:foo}bar}
165+
{{:foo} bar} {{!foo}bar} {{!foo} bar}

test/passing/tests/doc_comments-no-parse-docstrings.mli.ref

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,3 +650,7 @@ type x =
650650
{- baz}
651651
}
652652
*)
653+
654+
(** Space before a reference or link text is preserved. A newline is turned
655+
into a space. {{!ref}
656+
with newline} and {{!ref} with space}. *)

test/passing/tests/doc_comments-no-wrap.mli.ref

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -477,8 +477,9 @@ end
477477
{i fooooooooooooo oooooooo oooooooooo}
478478
{b fooooooooooooo oooooooooooo oooooo ooooooo} *)
479479

480-
(** {e foooooooo oooooooooo ooooooooo ooooooooo} {{!some ref} fooooooooooooo
481-
oooooooo oooooooooo} {b fooooooooooooo oooooooooooo oooooo ooooooo} *)
480+
(** {e foooooooo oooooooooo ooooooooo ooooooooo}
481+
{{!some ref} fooooooooooooo oooooooo oooooooooo}
482+
{b fooooooooooooo oooooooooooo oooooo ooooooo} *)
482483

483484
(** foooooooooooooooooooooooooooooooooooooooooooooooooo foooooooooooo
484485
{b eee + eee eee} *)
@@ -498,8 +499,7 @@ val k : int
498499
{i fooooooooooooo oooooooo oooooooooo
499500
{b fooooooooooooo oooooooooooo oooooo ooooooo}}} *)
500501

501-
(** {e
502-
{i fooooooooooooo oooooooo oooooooooo
502+
(** {e {i fooooooooooooo oooooooo oooooooooo
503503
{b fooooooooooooo oooooooooooo oooooo ooooooo}} foooooooo
504504
oooooooooo ooooooooo ooooooooo} *)
505505

@@ -692,3 +692,6 @@ type x =
692692
+ baz
693693
}
694694
} *)
695+
696+
(** Space before a reference or link text is preserved. A newline is turned
697+
into a space. {{!ref} with newline} and {{!ref} with space}. *)

test/passing/tests/doc_comments.mli

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,3 +657,7 @@ type x =
657657
{- baz}
658658
}
659659
*)
660+
661+
(** Space before a reference or link text is preserved. A newline is turned
662+
into a space. {{!ref}
663+
with newline} and {{!ref} with space}. *)

test/passing/tests/doc_comments.mli.ref

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -477,8 +477,9 @@ end
477477
{i fooooooooooooo oooooooo oooooooooo}
478478
{b fooooooooooooo oooooooooooo oooooo ooooooo} *)
479479

480-
(** {e foooooooo oooooooooo ooooooooo ooooooooo} {{!some ref} fooooooooooooo
481-
oooooooo oooooooooo} {b fooooooooooooo oooooooooooo oooooo ooooooo} *)
480+
(** {e foooooooo oooooooooo ooooooooo ooooooooo}
481+
{{!some ref} fooooooooooooo oooooooo oooooooooo}
482+
{b fooooooooooooo oooooooooooo oooooo ooooooo} *)
482483

483484
(** foooooooooooooooooooooooooooooooooooooooooooooooooo foooooooooooo
484485
{b eee + eee eee} *)
@@ -498,8 +499,7 @@ val k : int
498499
{i fooooooooooooo oooooooo oooooooooo
499500
{b fooooooooooooo oooooooooooo oooooo ooooooo}}} *)
500501

501-
(** {e
502-
{i fooooooooooooo oooooooo oooooooooo
502+
(** {e {i fooooooooooooo oooooooo oooooooooo
503503
{b fooooooooooooo oooooooooooo oooooo ooooooo}} foooooooo
504504
oooooooooo ooooooooo ooooooooo} *)
505505

@@ -686,3 +686,6 @@ type x =
686686
+ baz
687687
}
688688
} *)
689+
690+
(** Space before a reference or link text is preserved. A newline is turned
691+
into a space. {{!ref} with newline} and {{!ref} with space}. *)

vendor/odoc-parser/syntax.ml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,13 +281,15 @@ and delimited_inline_element_list :
281281
let first_token = peek input in
282282
match first_token.value with
283283
| `Space _ ->
284-
junk input;
284+
(* Preserve leading spaces in markups
285+
junk input; *)
285286
consume_elements ~at_start_of_line:false []
286287
(* [~at_start_of_line] is [false] here because the preceding token was some
287288
some markup like '{b', and we didn't move to the next line, so the next
288289
token will not be the first non-whitespace token on its line. *)
289290
| `Single_newline _ ->
290-
junk input;
291+
(* Preserve leading spaces in markups
292+
junk input; *)
291293
consume_elements ~at_start_of_line:true []
292294
| `Blank_line _ as blank ->
293295
(* In case the markup is immediately followed by a blank line, the error

0 commit comments

Comments
 (0)