diff --git a/bin/ocaml/ocaml_merlin.ml b/bin/ocaml/ocaml_merlin.ml index c901809128b..0e4ae2da7d7 100644 --- a/bin/ocaml/ocaml_merlin.ml +++ b/bin/ocaml/ocaml_merlin.ml @@ -99,21 +99,45 @@ end = struct let load_merlin_file file = (* We search for an appropriate merlin configuration in the current directory and its parents *) + let get_file_config_at_path p = + match Merlin.Processed.load_file p with + | Error msg -> Some (Merlin_conf.make_error msg) + | Ok config -> Merlin.Processed.get config ~file + in + let basename = Path.Build.set_extension file ~ext:"" |> Path.Build.basename in + let good_names = + List.map + ~f:(fun pref -> Printf.sprintf "%s-%s" pref basename) + [ "lib"; "exe"; "melange" ] + in let rec find_closest path = + let merlin_paths = get_merlin_files_paths path in + (* Now we want to look for: + 1. an exact match + 2. an approximate match + 3. recursing to parent directory + *) match - get_merlin_files_paths path - |> List.find_map ~f:(fun file_path -> - (* FIXME we are racing against the build system writing these - files here *) - match Merlin.Processed.load_file file_path with - | Error msg -> Some (Merlin_conf.make_error msg) - | Ok config -> Merlin.Processed.get config ~file) + List.find merlin_paths ~f:(fun p -> + List.mem good_names (Path.basename p) ~equal:String.equal) with - | Some p -> Some p + | Some p -> + (* Found exact match: we are done *) + get_file_config_at_path p | None -> - (match Path.Build.parent path with - | None -> None - | Some dir -> find_closest dir) + (* looking for approximate match *) + (match + List.find_map merlin_paths ~f:(fun file_path -> + (* FIXME we are racing against the build system writing these + files here *) + get_file_config_at_path file_path) + with + | Some p -> Some p + | None -> + (* Otherwise, recurse upwards *) + (match Path.Build.parent path with + | None -> None + | Some dir -> find_closest dir)) in match find_closest (Path.Build.parent_exn file) with | Some x -> x diff --git a/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/dune-project b/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/dune-project new file mode 100644 index 00000000000..42c0c167431 --- /dev/null +++ b/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/dune-project @@ -0,0 +1 @@ +(lang dune 1.10) diff --git a/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/multi-exes/bin/b.ml b/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/multi-exes/bin/b.ml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/multi-exes/bin/c.ml b/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/multi-exes/bin/c.ml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/multi-exes/bin/dune b/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/multi-exes/bin/dune new file mode 100644 index 00000000000..2a839c8b763 --- /dev/null +++ b/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/multi-exes/bin/dune @@ -0,0 +1,6 @@ +(executable + (name b)) + +(executable + (name c) + (libraries lib)) diff --git a/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/multi-exes/lib/dune b/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/multi-exes/lib/dune new file mode 100644 index 00000000000..67263ab7cf8 --- /dev/null +++ b/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/multi-exes/lib/dune @@ -0,0 +1,2 @@ +(library + (name lib)) diff --git a/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/multi-exes/lib/lib.ml b/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/multi-exes/lib/lib.ml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/run.t b/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/run.t new file mode 100644 index 00000000000..b5f16c33dd2 --- /dev/null +++ b/test/blackbox-tests/test-cases/merlin/merlin-multi-exes.t/run.t @@ -0,0 +1,15 @@ + $ ocamlc_where="$(ocamlc -where)" + $ export BUILD_PATH_PREFIX_MAP="/OCAMLC_WHERE=$ocamlc_where:$BUILD_PATH_PREFIX_MAP" + + $ FILE=$PWD/multi-exes/bin/b.ml + $ printf "(4:File%d:%s)" ${#FILE} $FILE | dune ocaml-merlin + ((5:ERROR71:No config found for file multi-exes/bin/b.ml. Try calling 'dune build'.)) + + $ dune build @check + + $ printf "(4:File%d:%s)" ${#FILE} $FILE | dune ocaml-merlin | sed -E "s/[[:digit:]]+:/\?:/g" + ((?:INDEX?:$TESTCASE_ROOT/_build/default/multi-exes/bin/.c.eobjs/cctx.ocaml-index)(?:INDEX?:$TESTCASE_ROOT/_build/default/multi-exes/bin/.b.eobjs/cctx.ocaml-index)(?:INDEX?:$TESTCASE_ROOT/_build/default/multi-exes/lib/.lib.objs/cctx.ocaml-index)(?:STDLIB?:/OCAMLC_WHERE)(?:SOURCE_ROOT?:$TESTCASE_ROOT)(?:EXCLUDE_QUERY_DIR)(?:B?:$TESTCASE_ROOT/_build/default/multi-exes/bin/.b.eobjs/byte)(?:S?:$TESTCASE_ROOT/multi-exes/bin)(?:FLG(?:-w?:@1..3@5..28@30..39@43@46..47@49..57@61..62-?:-strict-sequence?:-strict-formats?:-short-paths?:-keep-locs?:-g))(?:UNIT_NAME?:b)) + + $ FILE=$PWD/multi-exes/bin/c.ml + $ printf "(4:File%d:%s)" ${#FILE} $FILE | dune ocaml-merlin | sed -E "s/[[:digit:]]+:/\?:/g" + ((?:INDEX?:$TESTCASE_ROOT/_build/default/multi-exes/bin/.c.eobjs/cctx.ocaml-index)(?:INDEX?:$TESTCASE_ROOT/_build/default/multi-exes/bin/.b.eobjs/cctx.ocaml-index)(?:INDEX?:$TESTCASE_ROOT/_build/default/multi-exes/lib/.lib.objs/cctx.ocaml-index)(?:STDLIB?:/OCAMLC_WHERE)(?:SOURCE_ROOT?:$TESTCASE_ROOT)(?:EXCLUDE_QUERY_DIR)(?:B?:$TESTCASE_ROOT/_build/default/multi-exes/bin/.c.eobjs/byte)(?:B?:$TESTCASE_ROOT/_build/default/multi-exes/lib/.lib.objs/byte)(?:S?:$TESTCASE_ROOT/multi-exes/bin)(?:S?:$TESTCASE_ROOT/multi-exes/lib)(?:FLG(?:-w?:@1..3@5..28@30..39@43@46..47@49..57@61..62-?:-strict-sequence?:-strict-formats?:-short-paths?:-keep-locs?:-g))(?:UNIT_NAME?:c))