diff --git a/CHANGES.md b/CHANGES.md
index d4dd54ed1c..10bf17bdce 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -35,7 +35,8 @@
- Fix missing katex headers (@panglesd, #1096)
- Fix resolution of module synopses in {!modules} lists that require
--open (@jonludlam, #1104}
-- Fix top comment not being taken from includes often enough (#1117, @panglesd)
+- Fix top comment not being taken from includes often enough (@panglesd, #1117)
+- Fixed 404 links from search results (@panglesd, #1108)
# 2.4.0
diff --git a/src/search/html.ml b/src/search/html.ml
index de102fceda..747d45e88e 100644
--- a/src/search/html.ml
+++ b/src/search/html.ml
@@ -3,11 +3,22 @@ type html = Html_types.div_content Tyxml.Html.elt
open Odoc_model
open Lang
-let url id =
- match
- Odoc_document.Url.from_identifier ~stop_before:false
- (id :> Odoc_model.Paths.Identifier.t)
- with
+let url { Entry.id; kind; doc = _ } =
+ let open Entry in
+ let stop_before =
+ (* Some module/module types/... might not have an expansion, so we need to
+ be careful and set [stop_before] to [true] for those kind of search
+ entries, to avoid linking to an inexistant page.
+
+ Docstring do not have an ID in the model, and use the ID from the parent
+ signature in search entries. Therefore, links to doc comments need
+ [stop_before] to be [false] to point to the page where they are present.
+
+ Values, types, ... are not sensitive to [stop_before], allowing us to
+ shorten the match. *)
+ match kind with Doc _ -> false | _ -> true
+ in
+ match Odoc_document.Url.from_identifier ~stop_before id with
| Ok url ->
let config =
Odoc_html.Config.v ~search_result:true ~semantic_uris:false
diff --git a/src/search/html.mli b/src/search/html.mli
index 80065848e5..dd66127908 100644
--- a/src/search/html.mli
+++ b/src/search/html.mli
@@ -4,9 +4,7 @@ type html = Html_types.div_content Tyxml.Html.elt
val of_entry : Entry.t -> html list
-val url :
- Odoc_model.Paths.Identifier.Any.t ->
- (string, Odoc_document.Url.Error.t) Result.result
+val url : Entry.t -> (string, Odoc_document.Url.Error.t) Result.result
(** The below is intended for search engine that do not use the Json output but
Odoc as a library. Most search engine will use their own representation
diff --git a/src/search/json_index/json_display.ml b/src/search/json_index/json_display.ml
index c51ea9e71b..e269291cab 100644
--- a/src/search/json_index/json_display.ml
+++ b/src/search/json_index/json_display.ml
@@ -1,7 +1,7 @@
open Odoc_search
-let of_entry { Entry.id; doc = _; kind = _ } h =
- match Html.url id with
+let of_entry entry h =
+ match Html.url entry with
| Result.Ok url ->
let html =
h
diff --git a/test/search/dune b/test/search/dune
index a79b344326..058962202d 100644
--- a/test/search/dune
+++ b/test/search/dune
@@ -8,4 +8,4 @@
(cram
(deps %{bin:odoc} %{bin:odoc_print})
(enabled_if
- (>= %{ocaml_version} 4.04.0)))
+ (>= %{ocaml_version} 4.08.0)))
diff --git a/test/search/html_search.t/run.t b/test/search/html_search.t/run.t
index c0d7763175..755ec401b3 100644
--- a/test/search/html_search.t/run.t
+++ b/test/search/html_search.t/run.t
@@ -108,9 +108,9 @@ The index file, one entry per line:
{"id":[{"kind":"Page","name":"page"},{"kind":"Label","name":"a-title"}],"doc":"A title","kind":{"kind":"Doc","subkind":"Heading"},"display":{"url":"page/index.html#a-title","html":"doc
page.a-title
mod
J
a paragraph one
mod
Main
mod
Main.I
mod
Main.M
mod
Main.X
mod
Main.I
mod
Main.M
mod
Main.X
type
Main.t = int
A comment
type
Main.tdzdz = A of int * int | B of int list * int
A comment aaaaaaaaaa
type
Main.M.t
dsdsd
A title