Skip to content

Commit 2f1cb4d

Browse files
authored
feat: Add merlin support to dune tools (#12972)
Closes #12915
2 parents 894ece7 + 614b233 commit 2f1cb4d

File tree

10 files changed

+182
-1
lines changed

10 files changed

+182
-1
lines changed

bin/tools/group.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ module Exec = struct
1515
; Opam_publish
1616
; Dune_release
1717
; Ocaml_index
18+
; Merlin
1819
]
1920
~f:Tools_common.exec_command)
2021
;;

src/dune_pkg/dev_tool.ml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type t =
1010
| Opam_publish
1111
| Dune_release
1212
| Ocaml_index
13+
| Merlin
1314

1415
let to_dyn = function
1516
| Ocamlformat -> Dyn.variant "Ocamlformat" []
@@ -21,6 +22,7 @@ let to_dyn = function
2122
| Opam_publish -> Dyn.variant "Opam_publish" []
2223
| Dune_release -> Dyn.variant "Dune_release" []
2324
| Ocaml_index -> Dyn.variant "Ocaml_index" []
25+
| Merlin -> Dyn.variant "Merlin" []
2426
;;
2527

2628
let all =
@@ -33,6 +35,7 @@ let all =
3335
; Opam_publish
3436
; Dune_release
3537
; Ocaml_index
38+
; Merlin
3639
]
3740
;;
3841

@@ -57,6 +60,8 @@ let equal a b =
5760
| Dune_release, _ -> false
5861
| _, Dune_release -> false
5962
| Ocaml_index, Ocaml_index -> true
63+
| Ocaml_index, _ | _, Ocaml_index -> false
64+
| Merlin, Merlin -> true
6065
;;
6166

6267
let hash = Poly.hash
@@ -71,6 +76,7 @@ let package_name = function
7176
| Opam_publish -> Package_name.of_string "opam-publish"
7277
| Dune_release -> Package_name.of_string "dune-release"
7378
| Ocaml_index -> Package_name.of_string "ocaml-index"
79+
| Merlin -> Package_name.of_string "merlin"
7480
;;
7581

7682
let of_package_name package_name =
@@ -84,6 +90,7 @@ let of_package_name package_name =
8490
| "opam-publish" -> Opam_publish
8591
| "dune-release" -> Dune_release
8692
| "ocaml-index" -> Ocaml_index
93+
| "merlin" -> Merlin
8794
| other -> User_error.raise [ Pp.textf "No such dev tool: %s" other ]
8895
;;
8996

@@ -97,6 +104,7 @@ let exe_name = function
97104
| Opam_publish -> "opam-publish"
98105
| Dune_release -> "dune-release"
99106
| Ocaml_index -> "ocaml-index"
107+
| Merlin -> "ocamlmerlin"
100108
;;
101109

102110
let exe_path_components_within_package t = [ "bin"; exe_name t ]
@@ -110,5 +118,5 @@ let needs_to_build_with_same_compiler_as_project = function
110118
false
111119
| Opam_publish -> false
112120
| Dune_release -> false
113-
| Utop | Odoc | Ocamllsp | Ocaml_index | Odig -> true
121+
| Utop | Odoc | Ocamllsp | Ocaml_index | Odig | Merlin -> true
114122
;;

src/dune_pkg/dev_tool.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ type t =
88
| Opam_publish
99
| Dune_release
1010
| Ocaml_index
11+
| Merlin
1112

1213
val to_dyn : t -> Dyn.t
1314
val all : t list

test/blackbox-tests/test-cases/pkg/dev-tools-help-message.t

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ Output the help text:
4848
ocamllsp executable (pass flags to ocamllsp after the '--'
4949
argument, such as 'dune tools exec ocamllsp -- --help').
5050

51+
ocamlmerlin [OPTION]… [ARGS]…
52+
Wrapper for running ocamlmerlin intended to be run automatically
53+
by a text editor. All positional arguments will be passed to the
54+
ocamlmerlin executable (pass flags to ocamlmerlin after the '--'
55+
argument, such as 'dune tools exec ocamlmerlin -- --help').
56+
5157
odig [OPTION]… [ARGS]…
5258
Wrapper for running odig intended to be run automatically by a
5359
text editor. All positional arguments will be passed to the odig
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
Test that the "dune tools exec ocamlmerlin" command causes merlin to be
2+
locked, built and run when the command is run from a dune project with
3+
a lockdir containing an "ocaml" lockfile.
4+
5+
$ . ../helpers.sh
6+
$ . ./helpers.sh
7+
8+
$ mkrepo
9+
$ make_mock_merlin_package
10+
$ mkpkg ocaml 5.2.0
11+
12+
$ setup_merlin_workspace
13+
14+
$ cat > dune-project <<EOF
15+
> (lang dune 3.16)
16+
>
17+
> (package
18+
> (name foo)
19+
> (allow_empty))
20+
> EOF
21+
22+
$ make_lockdir
23+
$ make_lockpkg ocaml <<EOF
24+
> (version 5.2.0)
25+
> EOF
26+
27+
$ dune tools exec ocamlmerlin
28+
Solution for _build/.dev-tools.locks/merlin:
29+
- merlin.0.0.1
30+
- ocaml.5.2.0
31+
Running 'ocamlmerlin'
32+
hello from fake ocamlmerlin
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
Test that after evaling the output of 'dune tools env', the first ocamlmerlin
2+
executable in PATH is the one installed by dune as a dev tool.
3+
4+
$ . ../helpers.sh
5+
$ . ./helpers.sh
6+
7+
$ mkrepo
8+
$ make_mock_merlin_package
9+
$ mkpkg ocaml 5.2.0
10+
11+
$ setup_merlin_workspace
12+
13+
$ cat > dune-project <<EOF
14+
> (lang dune 3.16)
15+
>
16+
> (package
17+
> (name foo)
18+
> (allow_empty))
19+
> EOF
20+
21+
$ make_lockdir
22+
$ make_lockpkg ocaml <<EOF
23+
> (version 5.2.0)
24+
> EOF
25+
26+
First install the tool:
27+
$ dune tools exec ocamlmerlin
28+
Solution for _build/.dev-tools.locks/merlin:
29+
- merlin.0.0.1
30+
- ocaml.5.2.0
31+
Running 'ocamlmerlin'
32+
hello from fake ocamlmerlin
33+
34+
Now check that 'dune tools env' puts the dev tool in PATH:
35+
$ eval $(dune tools env)
36+
$ which ocamlmerlin
37+
$TESTCASE_ROOT/_build/_private/default/.dev-tool/merlin/target/bin/ocamlmerlin
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
Test that if the version of the "ocaml" package in the project's
2+
lockdir changes then the merlin dev tool is re-locked to be built
3+
with the version of the ocaml compiler now in the project's
4+
lockdir. This is necessary because merlin must be compiled with the
5+
same version of the ocaml compiler as the code that it's analyzing.
6+
7+
$ . ../helpers.sh
8+
$ . ./helpers.sh
9+
10+
$ mkrepo
11+
$ make_mock_merlin_package
12+
$ mkpkg ocaml 5.2.0
13+
$ mkpkg ocaml 5.1.0
14+
15+
$ setup_merlin_workspace
16+
17+
$ cat > dune-project <<EOF
18+
> (lang dune 3.16)
19+
>
20+
> (package
21+
> (name foo)
22+
> (allow_empty))
23+
> EOF
24+
25+
$ make_lockdir
26+
$ make_lockpkg ocaml <<EOF
27+
> (version 5.2.0)
28+
> EOF
29+
30+
Initially merlin will depend on ocaml.5.2.0 to match the project.
31+
$ dune tools exec ocamlmerlin
32+
Solution for _build/.dev-tools.locks/merlin:
33+
- merlin.0.0.1
34+
- ocaml.5.2.0
35+
Running 'ocamlmerlin'
36+
hello from fake ocamlmerlin
37+
$ cat "${dev_tool_lock_dir}"/ocaml.pkg
38+
(version 5.2.0)
39+
40+
We can re-run "dune tools exec ocamlmerlin" without relocking or rebuilding.
41+
$ dune tools exec ocamlmerlin
42+
Running 'ocamlmerlin'
43+
hello from fake ocamlmerlin
44+
45+
Change the version of ocaml that the project depends on.
46+
$ make_lockpkg ocaml <<EOF
47+
> (version 5.1.0)
48+
> EOF
49+
50+
Running "dune tools exec ocamlmerlin" causes merlin to be relocked and rebuilt
51+
before running. Merlin now depends on ocaml.5.1.0.
52+
$ dune tools exec ocamlmerlin
53+
The version of the compiler package ("ocaml") in this project's lockdir has
54+
changed to 5.1.0 (formerly the compiler version was 5.2.0). The dev-tool
55+
"merlin" will be re-locked and rebuilt with this version of the compiler.
56+
Solution for _build/.dev-tools.locks/merlin:
57+
- merlin.0.0.1
58+
- ocaml.5.1.0
59+
Running 'ocamlmerlin'
60+
hello from fake ocamlmerlin
61+
$ cat "${dev_tool_lock_dir}"/ocaml.pkg
62+
(version 5.1.0)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
(cram
2+
(deps helpers.sh)
3+
(applies_to :whole_subtree))
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
dev_tool_lock_dir="_build/.dev-tools.locks/merlin"
2+
3+
# Create a dune-workspace file with mock repos configured for the main
4+
# project lockdir and the merlin dev-tool lockdir.
5+
setup_merlin_workspace() {
6+
cat > dune-workspace <<EOF
7+
(lang dune 3.20)
8+
(lock_dir
9+
(path "${dev_tool_lock_dir}")
10+
(repositories mock))
11+
(lock_dir
12+
(repositories mock))
13+
(repository
14+
(name mock)
15+
(url "file://$(pwd)/mock-opam-repository"))
16+
(pkg enabled)
17+
EOF
18+
}
19+
20+
# Create a fake merlin package containing an executable that
21+
# just prints a message.
22+
make_mock_merlin_package() {
23+
mkpkg merlin <<EOF
24+
install: [
25+
[ "sh" "-c" "echo '#!/bin/sh' > %{bin}%/ocamlmerlin" ]
26+
[ "sh" "-c" "echo 'echo hello from fake ocamlmerlin' >> %{bin}%/ocamlmerlin" ]
27+
[ "sh" "-c" "chmod a+x %{bin}%/ocamlmerlin" ]
28+
]
29+
EOF
30+
}

test/blackbox-tests/test-cases/pkg/ocamllsp/dev-tool-ocamllsp-env-path-var.t

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Confirm that each dev tool's bin directory is now in PATH:
2828
- ocaml.5.2.0
2929
- ocaml-lsp-server.0.0.1
3030
Running 'ocamllsp'
31+
$TESTCASE_ROOT/_build/_private/default/.dev-tool/merlin/target/bin
3132
$TESTCASE_ROOT/_build/_private/default/.dev-tool/ocaml-index/target/bin
3233
$TESTCASE_ROOT/_build/_private/default/.dev-tool/dune-release/target/bin
3334
$TESTCASE_ROOT/_build/_private/default/.dev-tool/opam-publish/target/bin

0 commit comments

Comments
 (0)