Skip to content

Commit

Permalink
[merlin] Handle filenames with dot-separated sections (#4264)
Browse files Browse the repository at this point in the history
* Split filename on `.` and use the first part for config matching
* Illustrate usage with some tests
* Add some documentation about naming preprocessed files.

Signed-off-by: Ulysse Gérard <[email protected]>
  • Loading branch information
voodoos authored Feb 22, 2021
1 parent c507979 commit c36df0b
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 6 deletions.
20 changes: 15 additions & 5 deletions doc/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,8 @@ There's a few aliases that dune automatically creates for the user
defined in that directory.

* ``check`` - This alias will build the minimal set of targets required for
tooling support. Essentially, this is ``.cmi``, ``.cmt``, ``.cmti``, and
``.merlin`` files.
tooling support. Essentially, this is ``.cmi``, ``.cmt``, ``.cmti`` files and
Merlin configurations.

Variables for artifacts
-----------------------
Expand Down Expand Up @@ -587,6 +587,16 @@ be un-commented afterward. This feature does not aim at writing exact or correct
``.merlin`` files, its sole purpose is to lessen the burden of writing the
configuration from scratch.

Both these commands also support an optional path to specify the target
directory. This directory must be in a Dune workspace and the project must have
already been built.
Non-standard filenames
----------------------

Merlin configuration loading is based on filename. That means that if you have
files which are preprocessed by custom rules before they are built, they should
respect the following naming convention: the unprocessed file should start with
the name of the resulting processed file followed by a dot and then the rest
does not matter. Only the name before the first dot will be used by Dune to
match with available configurations.

For example, if you use the ``cppo`` preprocessor to generate the file
``real_module_name.ml`` then the source file could be named
``real_module_name.cppo.ml``.
9 changes: 8 additions & 1 deletion src/dune_rules/merlin.ml
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,14 @@ module Processed = struct
Buffer.contents b

let get { modules; pp_config; config } ~filename =
let fname = Filename.remove_extension filename |> String.lowercase in
(* We only match the first part of the filename : foo.ml -> foo foo.cppo.ml
-> foo *)
let fname =
String.lsplit2 filename ~on:'.'
|> Option.map ~f:fst
|> Option.value ~default:filename
|> String.lowercase
in
List.find_opt modules ~f:(fun name ->
let fname' = Module_name.to_string name |> String.lowercase in
String.equal fname fname')
Expand Down
5 changes: 5 additions & 0 deletions test/blackbox-tests/test-cases/merlin/server.t/dune
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@
(name main)
(modules main lib2)
(libraries mylib mylib3))

(executable
(name not-a-module-name)
(modules not-a-module-name)
(flags :standard -w -24))
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print_endline "I do not bear a valid module name."
25 changes: 25 additions & 0 deletions test/blackbox-tests/test-cases/merlin/server.t/run.t
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,28 @@
> (4:File${#FILE}:$FILE)
> EOF
((?:STDLIB?:OPAM_PREFIX/lib/ocaml)(?:EXCLUDE_QUERY_DIR)(?:B?:$TESTCASE_ROOT/_build/default/.mylib.objs/byte)(?:B?:$TESTCASE_ROOT/_build/default/.mylib3.objs/byte)(?:S?:$TESTCASE_ROOT)(?:FLG(?:-open?:Mylib?:-w?:@1..3@5..28@30..39@43@46..47@49..57@61..62-?:-strict-sequence?:-strict-formats?:-short-paths?:-keep-locs)))

If a file has a name of the kind `module_name.xx.xxx.ml/i`
we consider it as ``module_name.ml/i`
This can be useful when some build scripts perform custom
preprocessing and copy files around.
$ FILE=lib3.foobar.ml
$ dune ocaml-merlin <<EOF | sed -E "s/[[:digit:]]+:/\?:/g" | sed 's#'$(opam config var prefix)'#OPAM_PREFIX#'
> (4:File${#FILE}:$FILE)
> EOF
((?:STDLIB?:OPAM_PREFIX/lib/ocaml)(?:EXCLUDE_QUERY_DIR)(?:B?:$TESTCASE_ROOT/_build/default/.mylib.objs/byte)(?:B?:$TESTCASE_ROOT/_build/default/.mylib3.objs/byte)(?:S?:$TESTCASE_ROOT)(?:FLG(?:-open?:Mylib?:-w?:@1..3@5..28@30..39@43@46..47@49..57@61..62-?:-strict-sequence?:-strict-formats?:-short-paths?:-keep-locs)))

If a directory has no configuration the configuration of its parent is used
This can be useful when some build scripts copy files from subdirectories.
$ FILE=some_sub_dir/lib3.foobar.ml
$ dune ocaml-merlin <<EOF | sed -E "s/[[:digit:]]+:/\?:/g" | sed 's#'$(opam config var prefix)'#OPAM_PREFIX#'
> (4:File${#FILE}:$FILE)
> EOF
((?:STDLIB?:OPAM_PREFIX/lib/ocaml)(?:EXCLUDE_QUERY_DIR)(?:B?:$TESTCASE_ROOT/_build/default/.mylib.objs/byte)(?:B?:$TESTCASE_ROOT/_build/default/.mylib3.objs/byte)(?:S?:$TESTCASE_ROOT)(?:FLG(?:-open?:Mylib?:-w?:@1..3@5..28@30..39@43@46..47@49..57@61..62-?:-strict-sequence?:-strict-formats?:-short-paths?:-keep-locs)))

Test of an valid invalid module name
$ FILE=not-a-module-name.ml
$ dune ocaml-merlin <<EOF | sed -E "s/[[:digit:]]+:/\?:/g" | sed 's#'$(opam config var prefix)'#OPAM_PREFIX#'
> (4:File${#FILE}:$FILE)
> EOF
((?:STDLIB?:OPAM_PREFIX/lib/ocaml)(?:EXCLUDE_QUERY_DIR)(?:B?:$TESTCASE_ROOT/_build/default/.not-a-module-name.eobjs/byte)(?:S?:$TESTCASE_ROOT)(?:FLG(?:-w?:@1..3@5..28@30..39@43@46..47@49..57@61..62-?:-strict-sequence?:-strict-formats?:-short-paths?:-keep-locs?:-w?:-24)))

0 comments on commit c36df0b

Please sign in to comment.