@@ -35,6 +35,7 @@ let empty = Mconfig_dot.empty_config
3535module Process = struct
3636 type nonrec t =
3737 { pid : Pid .t
38+ ; prog : string
3839 ; initial_cwd : string
3940 ; stdin : Lev_fiber.Io .output Lev_fiber.Io .t
4041 ; stdout : Lev_fiber.Io .input Lev_fiber.Io .t
@@ -52,30 +53,42 @@ module Process = struct
5253 | Unix. WEXITED n ->
5354 (match n with
5455 | 0 -> ()
55- | n -> Format. eprintf " dune finished with code = %d@.%!" n)
56- | WSIGNALED s -> Format. eprintf " dune finished signal = %d@.%!" s
56+ | n -> Format. eprintf " %s finished with code = %d@.%!" t.prog n)
57+ | WSIGNALED s -> Format. eprintf " %s finished signal = %d@.%!" t.prog s
5758 | WSTOPPED _ -> () );
5859 Format. eprintf " closed merlin process@.%s@." (Dyn. to_string @@ to_dyn t);
5960 Lev_fiber.Io. close t.stdin;
6061 Lev_fiber.Io. close t.stdout
6162 ;;
6263
6364 let start ~dir =
64- match Bin. which " dune" with
65+ let bin, args =
66+ (* the convention is that $OCAMLLSP_PROJECT_BUILD_SYSTEM executable has
67+ `ocaml-merlin` subcommand to start a merlin configuration server *)
68+ match Sys. getenv_opt " OCAMLLSP_PROJECT_BUILD_SYSTEM" with
69+ | None -> " dune" , [ " ocaml-merlin" ; " --no-print-directory" ]
70+ | Some bin -> bin, [ " ocaml-merlin" ]
71+ in
72+ match Bin. which bin with
6573 | None ->
6674 Jsonrpc.Response.Error. raise
6775 (Jsonrpc.Response.Error. make
6876 ~code: InternalError
69- ~message: " dune binary not found"
77+ ~message: ( Printf. sprintf " %s binary not found" bin)
7078 () )
7179 | Some prog ->
7280 let stdin_r, stdin_w = Unix. pipe () in
7381 let stdout_r, stdout_w = Unix. pipe () in
7482 Unix. set_close_on_exec stdin_w;
7583 let pid =
76- let argv = [ prog; " ocaml-merlin" ; " --no-print-directory" ] in
7784 Pid. of_int
78- (Spawn. spawn ~cwd: (Path dir) ~prog ~argv ~stdin: stdin_r ~stdout: stdout_w () )
85+ (Spawn. spawn
86+ ~cwd: (Path dir)
87+ ~prog
88+ ~argv: (prog :: args)
89+ ~stdin: stdin_r
90+ ~stdout: stdout_w
91+ () )
7992 in
8093 Unix. close stdin_r;
8194 Unix. close stdout_w;
@@ -94,7 +107,7 @@ module Process = struct
94107 let * stdin = make stdin_w Output in
95108 let + stdout = make stdout_r Input in
96109 let session = Lev_fiber_csexp.Session. create ~socket: false stdout stdin in
97- { pid; initial_cwd = dir; stdin; stdout; session }
110+ { prog; pid; initial_cwd = dir; stdin; stdout; session }
98111 ;;
99112end
100113
@@ -146,7 +159,8 @@ module Entry = struct
146159 else (
147160 Table. remove t.db.running t.process.initial_cwd;
148161 Format. eprintf
149- " halting dune merlin process@.%s@."
162+ " halting %s merlin process@.%s@."
163+ t.process.prog
150164 (Dyn. to_string (Process. to_dyn t.process));
151165 Dot_protocol_io.Commands. halt t.process.session)
152166 ;;
@@ -211,10 +225,13 @@ let get_config (p : Process.t) ~workdir path_abs =
211225 Mconfig_dot. postprocess_config cfg, failures
212226 | Error (Merlin_dot_protocol. Unexpected_output msg ) -> empty, [ msg ]
213227 | Error (Csexp_parse_error _ ) ->
214- ( empty
215- , [ " ocamllsp could not load its configuration from the external reader. Building \
216- your project with `dune` might solve this issue."
217- ] )
228+ let suggest =
229+ Printf. sprintf
230+ " ocamllsp could not load its configuration from the external reader. Building \
231+ your project with `%s` might solve this issue."
232+ p.prog
233+ in
234+ empty, [ suggest ]
218235;;
219236
220237let file_exists fname =
@@ -223,7 +240,17 @@ let file_exists fname =
223240 | s -> s.st_kind <> S_DIR
224241;;
225242
226- let find_project_context start_dir =
243+ let check_project_root_markers ~workdir ~dir markers =
244+ List. find_map markers ~f: (fun f ->
245+ let fname = Filename. concat dir f in
246+ if file_exists fname
247+ then (
248+ let workdir = Misc. canonicalize_filename (Option. value ~default: dir workdir) in
249+ Some ({ workdir; process_dir = dir }, fname))
250+ else None )
251+ ;;
252+
253+ let find_dune_project_context start_dir =
227254 (* The workdir is the first directory we find which contains a [dune] file. We
228255 need to keep track of this folder because [dune ocaml-merlin] might be
229256 started from a folder that is a parent of the [workdir]. Thus we cannot
@@ -235,15 +262,9 @@ let find_project_context start_dir =
235262 let fnames = List. map ~f: (Filename. concat dir) [ " dune" ; " dune-file" ] in
236263 if List. exists ~f: file_exists fnames then Some dir else None
237264 in
238- let rec loop workdir dir =
265+ let rec loop ~ workdir ~ dir =
239266 match
240- List. find_map [ " dune-project" ; " dune-workspace" ] ~f: (fun f ->
241- let fname = Filename. concat dir f in
242- if file_exists fname
243- then (
244- let workdir = Misc. canonicalize_filename (Option. value ~default: dir workdir) in
245- Some ({ workdir; process_dir = dir }, fname))
246- else None )
267+ check_project_root_markers [ " dune-project" ; " dune-workspace" ] ~workdir ~dir
247268 with
248269 | Some s -> Some s
249270 | None ->
@@ -252,10 +273,18 @@ let find_project_context start_dir =
252273 then (
253274 (* Was this directory the workdir ? *)
254275 let workdir = map_workdir dir workdir in
255- loop workdir parent)
276+ loop ~ workdir ~dir: parent)
256277 else None
257278 in
258- loop None start_dir
279+ loop ~workdir: None ~dir: start_dir
280+ ;;
281+
282+ let find_project_context start_dir =
283+ match Sys. getenv_opt " OCAMLLSP_PROJECT_ROOT" with
284+ | Some dir ->
285+ let dir = Misc. canonicalize_filename dir in
286+ Some ({ workdir = dir; process_dir = dir }, " <merlin-config>" )
287+ | None -> find_dune_project_context start_dir
259288;;
260289
261290type nonrec t =
0 commit comments