diff --git a/doc/changes/8567.md b/doc/changes/8567.md new file mode 100644 index 00000000000..64cd6d2ca9d --- /dev/null +++ b/doc/changes/8567.md @@ -0,0 +1,3 @@ +- merlin: add optional `(merlin_reader CMD)` construct to `(dialect)` stanza to + configure a merlin reader (#8567, @andreypopp) + diff --git a/src/dune_rules/dialect.ml b/src/dune_rules/dialect.ml index e5f556f3fc8..56a876fadb2 100644 --- a/src/dune_rules/dialect.ml +++ b/src/dune_rules/dialect.ml @@ -11,9 +11,10 @@ module File_kind = struct ; preprocess : (Loc.t * Action.t) option ; format : (Loc.t * Action.t * string list) option ; print_ast : (Loc.t * Action.t) option + ; merlin_reader : (Loc.t * string list) option } - let encode { kind; extension; preprocess; format; print_ast } = + let encode { kind; extension; preprocess; format; print_ast; merlin_reader } = let open Dune_lang.Encoder in let kind = string @@ -33,10 +34,11 @@ module File_kind = struct "print_ast" Action.encode (Option.map ~f:(fun (_, x) -> x) print_ast) + ; field_o "merlin_reader" (list string) (Option.map ~f:snd merlin_reader) ]) ;; - let to_dyn { kind; extension; preprocess; format; print_ast } = + let to_dyn { kind; extension; preprocess; format; print_ast; merlin_reader } = let open Dyn in record [ "kind", Ml_kind.to_dyn kind @@ -44,6 +46,7 @@ module File_kind = struct ; "preprocess", option (fun (_, x) -> Action.to_dyn x) preprocess ; "format", option (fun (_, x, y) -> pair Action.to_dyn (list string) (x, y)) format ; "print_ast", option (fun (_, x) -> Action.to_dyn x) print_ast + ; "merlin_reader", option (fun (_, x) -> list string x) merlin_reader ] ;; end @@ -85,13 +88,17 @@ let decode = "format" (map ~f:(fun (loc, x) -> loc, x, []) (located Action.decode_dune_file)) and+ print_ast = field_o "print_ast" (located Action.decode_dune_file) + and+ merlin_reader = + field_o + "merlin_reader" + (Dune_lang.Syntax.since Stanza.syntax (3, 16) >>> located (repeat1 string)) and+ syntax_ver = Syntax.get_exn Stanza.syntax in let ver = 3, 9 in if syntax_ver < ver && Option.is_some (String.index_from extension 1 '.') then ( let what = "the possibility of defining extensions containing periods" in Syntax.Error.since loc Stanza.syntax ver ~what); - { File_kind.kind; extension; preprocess; format; print_ast } + { File_kind.kind; extension; preprocess; format; print_ast; merlin_reader } in fields (let+ name = field "name" string @@ -143,6 +150,13 @@ let print_ast { file_kinds; _ } ml_kind = x.print_ast ;; +let merlin_reader { file_kinds; _ } ml_kind = + let open Option.O in + let* dialect = Ml_kind.Dict.get file_kinds ml_kind in + let+ _, merlin_reader = dialect.merlin_reader in + merlin_reader +;; + let ocaml = let format kind = let flag_of_kind = function @@ -180,6 +194,7 @@ let ocaml = , format kind , [ ".ocamlformat"; ".ocamlformat-ignore"; ".ocamlformat-enable" ] ) ; print_ast = Some (Loc.none, print_ast kind) + ; merlin_reader = None } in let intf = Some (file_kind Ml_kind.Intf ".mli") in @@ -222,6 +237,7 @@ let reason = ; preprocess = Some (Loc.none, preprocess) ; format = Some (Loc.none, format, []) ; print_ast = Some (Loc.none, print_ast) + ; merlin_reader = None } in let intf = Some (file_kind Ml_kind.Intf ".rei") in @@ -251,6 +267,7 @@ let rescript = ; preprocess = Some (Loc.none, preprocess) ; format = Some (Loc.none, format, []) ; print_ast = None + ; merlin_reader = None } in let intf = Some (file_kind Ml_kind.Intf ".resi") in @@ -271,7 +288,12 @@ module DB = struct type t = { by_name : dialect String.Map.t ; by_extension : dialect Filename.Extension.Map.t - ; mutable extensions_for_merlin : string option Ml_kind.Dict.t list option + ; for_merlin : for_merlin Lazy.t + } + + and for_merlin = + { extensions : Filename.Extension.t option Ml_kind.Dict.t list + ; readers : Filename.Extension.t list String.Map.t } let fold { by_name; _ } = String.Map.fold by_name @@ -279,35 +301,49 @@ module DB = struct let empty = { by_name = String.Map.empty ; by_extension = Filename.Extension.Map.empty - ; extensions_for_merlin = None + ; for_merlin = lazy { extensions = []; readers = String.Map.empty } } ;; - let set_extensions_for_merlin t = - let v = - fold t ~init:[] ~f:(fun d s -> - let impl = extension d Ml_kind.Impl in - let intf = extension d Ml_kind.Intf in - if (* Only include dialects with no preprocessing and skip default file - extensions *) - preprocess d Ml_kind.Impl <> None - || preprocess d Ml_kind.Intf <> None - || (impl = extension ocaml Ml_kind.Impl && intf = extension ocaml Ml_kind.Intf) - then s - else { Ml_kind.Dict.impl; intf } :: s) - |> List.sort ~compare:(Ml_kind.Dict.compare (Option.compare String.compare)) + let compute_for_merlin = + let handle_ml_kind ~dialect kind readers = + let ext = extension dialect kind in + if ext = extension ocaml kind + then (* this is standard dialect, exclude *) None, readers + else ( + match ext, merlin_reader dialect kind with + | Some ext, Some reader -> Some ext, String.Map.add_exn readers ext reader + | _ -> + if preprocess dialect kind <> None + then (* we have preprocessor defined *) None, readers + else ext, readers) in - t.extensions_for_merlin <- Some v; - v + fun by_name -> + let extensions, readers = + String.Map.fold + by_name + ~init:([], String.Map.empty) + ~f:(fun dialect (extensions, readers) -> + let impl, readers = handle_ml_kind ~dialect Ml_kind.Impl readers in + let intf, readers = handle_ml_kind ~dialect Ml_kind.Intf readers in + let extensions = + match impl, intf with + | None, None -> extensions + | _ -> { Ml_kind.Dict.impl; intf } :: extensions + in + extensions, readers) + in + let extensions = + List.sort + ~compare:(Ml_kind.Dict.compare (Option.compare String.compare)) + extensions + in + { extensions; readers } ;; - let extensions_for_merlin t = - match t.extensions_for_merlin with - | Some s -> s - | None -> set_extensions_for_merlin t - ;; + let for_merlin t = Lazy.force t.for_merlin - let add { by_name; by_extension; extensions_for_merlin = _ } ~loc dialect = + let add { by_name; by_extension; for_merlin = _ } ~loc dialect = let by_name = match String.Map.add by_name dialect.name dialect with | Ok by_name -> by_name @@ -331,7 +367,7 @@ module DB = struct let by_extension = add_ext (add_ext by_extension dialect.file_kinds.intf) dialect.file_kinds.impl in - { by_name; by_extension; extensions_for_merlin = None } + { by_name; by_extension; for_merlin = lazy (compute_for_merlin by_name) } ;; let of_list dialects = List.fold_left ~f:(add ~loc:Loc.none) ~init:empty dialects diff --git a/src/dune_rules/dialect.mli b/src/dune_rules/dialect.mli index 6cb8b7a1680..7cd9b9b0ee8 100644 --- a/src/dune_rules/dialect.mli +++ b/src/dune_rules/dialect.mli @@ -43,8 +43,14 @@ module DB : sig val find_by_name : t -> string -> dialect option val find_by_extension : t -> Filename.Extension.t -> (dialect * Ml_kind.t) option val fold : t -> init:'a -> f:(dialect -> 'a -> 'a) -> 'a - val extensions_for_merlin : t -> Filename.Extension.t option Ml_kind.Dict.t list val to_dyn : t -> Dyn.t val builtin : t val is_default : t -> bool + + type for_merlin = + { extensions : string option Ml_kind.Dict.t list + ; readers : Filename.Extension.t list String.Map.t + } + + val for_merlin : t -> for_merlin end diff --git a/src/dune_rules/merlin/merlin.ml b/src/dune_rules/merlin/merlin.ml index 89781b27cda..fa70393ae8e 100644 --- a/src/dune_rules/merlin/merlin.ml +++ b/src/dune_rules/merlin/merlin.ml @@ -68,25 +68,30 @@ module Processed = struct type module_config = { opens : Module_name.t list ; module_ : Module.t + ; reader : string list option } - let dyn_of_module_config { opens; module_ } = + let dyn_of_module_config { opens; module_; reader } = let open Dyn in - record [ "opens", list Module_name.to_dyn opens; "module_", Module.to_dyn module_ ] + record + [ "opens", list Module_name.to_dyn opens + ; "module_", Module.to_dyn module_ + ; "reader", option (list string) reader + ] ;; (* ...but modules can have different preprocessing specifications*) type t = { config : config - ; per_module_config : module_config Path.Build.Map.t + ; per_file_config : module_config Path.Build.Map.t ; pp_config : pp_flag option Module_name.Per_item.t } - let to_dyn { config; per_module_config; pp_config } = + let to_dyn { config; per_file_config; pp_config } = let open Dyn in record [ "config", dyn_of_config config - ; "per_module_config", Path.Build.Map.to_dyn dyn_of_module_config per_module_config + ; "per_file_config", Path.Build.Map.to_dyn dyn_of_module_config per_file_config ; "pp_config", Module_name.Per_item.to_dyn (option dyn_of_pp_flag) pp_config ] ;; @@ -106,7 +111,7 @@ module Processed = struct ; flags = [ "-x" ] ; extensions = [ { Ml_kind.Dict.intf = None; impl = Some "ext" } ] } - ; per_module_config = Path.Build.Map.empty + ; per_file_config = Path.Build.Map.empty ; pp_config = (match Module_name.Per_item.of_mapping @@ -144,7 +149,7 @@ module Processed = struct | None, None -> None ;; - let to_sexp ~opens ~pp { stdlib_dir; obj_dirs; src_dirs; flags; extensions } = + let to_sexp ~opens ~pp ~reader { stdlib_dir; obj_dirs; src_dirs; flags; extensions } = let make_directive tag value = Sexp.List [ Atom tag; value ] in let make_directive_of_path tag path = make_directive tag (Sexp.Atom (serialize_path path)) @@ -185,8 +190,16 @@ module Processed = struct let+ impl, intf = get_ext x in make_directive "SUFFIX" (Sexp.Atom (Printf.sprintf "%s %s" impl intf))) in + let reader = + match reader with + | Some reader -> + [ make_directive "READER" (Sexp.List (List.map ~f:(fun r -> Sexp.Atom r) reader)) + ] + | None -> [] + in Sexp.List - (List.concat [ stdlib_dir; exclude_query_dir; obj_dirs; src_dirs; flags; suffixes ]) + (List.concat + [ stdlib_dir; exclude_query_dir; obj_dirs; src_dirs; flags; suffixes; reader ]) ;; let quote_for_dot_merlin s = @@ -231,39 +244,46 @@ module Processed = struct Buffer.contents b ;; - let get { per_module_config; pp_config; config } ~file = - (* We only match the first part of the filename : foo.ml -> foo foo.cppo.ml - -> foo *) + let get { per_file_config; pp_config; config } ~file = let open Option.O in - let+ { module_; opens } = - let find file = - let file_without_ext = remove_extension file in - Path.Build.Map.find per_module_config file_without_ext - in + let+ { module_; opens; reader } = + let find file = Path.Build.Map.find per_file_config file in match find file with | Some _ as s -> s - | None -> Copy_line_directive.DB.follow_while file ~f:find + | None -> + (match Copy_line_directive.DB.follow_while file ~f:find with + | Some _ as s -> s + | None -> + (* Fallback to handle preprocessed files (where the preprocessor has + the file extensison changed). + + We choose to fallback by a lookup by filename without extension. + + This is too rough but, really, preprocessors should emit copy + line directives instead and then Dune should have the database + similar to Copy_line_directive to handle this. *) + Path.Build.Map.find per_file_config (remove_extension file)) in let pp = Module_name.Per_item.get pp_config (Module.name module_) in - to_sexp ~opens ~pp config + to_sexp ~opens ~pp ~reader config ;; let print_file path = match load_file path with | Error msg -> Printf.eprintf "%s\n" msg - | Ok { per_module_config; pp_config; config } -> - let pp_one (source, { module_; opens }) = + | Ok { per_file_config; pp_config; config } -> + let pp_one (source, { module_; opens; reader }) = let open Pp.O in let name = Module.name module_ in let pp = Module_name.Per_item.get pp_config name in - let sexp = to_sexp ~opens ~pp config in + let sexp = to_sexp ~reader ~opens ~pp config in Pp.hvbox (Pp.textf "%s: %s" (Module_name.to_string name) (Path.Build.to_string source)) ++ Pp.newline ++ Pp.vbox (Sexp.pp sexp) in let pp = - Path.Build.Map.to_list per_module_config + Path.Build.Map.to_list per_file_config |> Pp.concat_map ~sep:Pp.cut ~f:pp_one |> Pp.vbox in @@ -288,7 +308,7 @@ module Processed = struct ~f: (fun (acc_pp, acc_obj, acc_src, acc_flags, acc_ext) - { per_module_config = _ + { per_file_config = _ ; pp_config ; config = { stdlib_dir = _; obj_dirs; src_dirs; flags; extensions } } @@ -335,6 +355,7 @@ module Unprocessed = struct ; source_dirs : Path.Source.Set.t ; objs_dirs : Path.Set.t ; extensions : string option Ml_kind.Dict.t list + ; readers : string list String.Map.t ; mode : Lib_mode.t } @@ -373,7 +394,7 @@ module Unprocessed = struct Path.Set.singleton @@ obj_dir_of_lib `Private mode (Obj_dir.of_local obj_dir) in let flags = Ocaml_flags.get flags mode in - let extensions = Dialect.DB.extensions_for_merlin dialects in + let { Dialect.DB.extensions; readers } = Dialect.DB.for_merlin dialects in let config = { stdlib_dir ; mode @@ -384,6 +405,7 @@ module Unprocessed = struct ; source_dirs ; objs_dirs ; extensions + ; readers } in { ident; config; modules } @@ -488,6 +510,7 @@ module Unprocessed = struct ; config = { stdlib_dir ; extensions + ; readers ; flags ; objs_dirs ; source_dirs @@ -562,24 +585,27 @@ module Unprocessed = struct in { Processed.stdlib_dir; src_dirs; obj_dirs; flags; extensions } and+ pp_config = pp_config t (Super_context.context sctx) ~expander in - let per_module_config = + let per_file_config = (* And copy for each module the resulting pp flags *) modules |> Modules.With_vlib.drop_vlib |> Modules.fold ~init:[] ~f:(fun m init -> - Module.sources m - |> Path.Build.Set.of_list_map ~f:(fun src -> - Path.as_in_build_dir_exn src |> remove_extension) + Module.sources_without_pp m + |> Path.Build.Set.of_list_map ~f:(fun src -> Path.as_in_build_dir_exn src) |> Path.Build.Set.fold ~init ~f:(fun src acc -> let config = { Processed.module_ = Module.set_pp m None ; opens = Modules.With_vlib.local_open modules m + ; reader = String.Map.find readers (Path.Build.extension src) } in - (src, config) :: acc)) - |> Path.Build.Map.of_list_exn + (* we add the config with and without the extension, the latter is + needed for a fallback in this file's [get] function. *) + let src_without_extension = remove_extension src in + (src, config) :: (src_without_extension, config) :: acc)) + |> Path.Build.Map.of_list_reduce ~f:(fun existing _ -> existing) in - { Processed.pp_config; config; per_module_config } + { Processed.pp_config; config; per_file_config } ;; end diff --git a/src/dune_rules/module.ml b/src/dune_rules/module.ml index 21d5053f86b..6ea97e25ad9 100644 --- a/src/dune_rules/module.ml +++ b/src/dune_rules/module.ml @@ -3,6 +3,9 @@ open Import module File = struct type t = { path : Path.t + ; original_path : Path.t + (* while path can be changed for a module (when it is being pp'ed), the + original_path stays the same and points to an original source file *) ; dialect : Dialect.t } @@ -11,16 +14,17 @@ module File = struct fields @@ let+ path = field "path" (Dune_lang.Path.Local.decode ~dir) in (* TODO do not just assume the dialect is OCaml *) - { path; dialect = Dialect.ocaml } + { path; original_path = path; dialect = Dialect.ocaml } ;; - let encode { path; dialect = _ } ~dir = + let encode { path; original_path = _; dialect = _ } ~dir = let open Dune_lang.Encoder in record_fields [ field "path" (Dune_lang.Path.Local.encode ~dir) path ] ;; let dialect t = t.dialect let path t = t.path + let original_path t = t.original_path let version_installed t ~src_root ~install_dir = let path = @@ -32,11 +36,15 @@ module File = struct { t with path } ;; - let make dialect path = { dialect; path } + let make dialect path = { dialect; path; original_path = path } - let to_dyn { path; dialect } = + let to_dyn { path; original_path; dialect } = let open Dyn in - record [ "path", Path.to_dyn path; "dialect", Dyn.string @@ Dialect.name dialect ] + record + [ "path", Path.to_dyn path + ; "original_path", Path.to_dyn original_path + ; "dialect", Dyn.string @@ Dialect.name dialect + ] ;; end @@ -305,17 +313,17 @@ let wrapped_compat t = assert (t.visibility = Public); let source = let impl = - Some - { File.dialect = Dialect.ocaml - ; path = - (* Option.value_exn cannot fail because we disallow wrapped - compatibility mode for virtual libraries. That means none of the - modules are implementing a virtual module, and therefore all have - a source dir *) - Path.L.relative - (src_dir t) - [ ".wrapped_compat"; Module_name.Path.to_string t.source.path ^ ml_gen ] - } + let path = + (* TODO(andreypopp): is this comment still relevant? *) + (* Option.value_exn cannot fail because we disallow wrapped + compatibility mode for virtual libraries. That means none of the + modules are implementing a virtual module, and therefore all have + a source dir *) + Path.L.relative + (src_dir t) + [ ".wrapped_compat"; Module_name.Path.to_string t.source.path ^ ml_gen ] + in + Some { File.dialect = Dialect.ocaml; path; original_path = path } in { t.source with files = { intf = None; impl } } in @@ -330,6 +338,12 @@ let sources t = ~f:(Option.map ~f:(fun (x : File.t) -> x.path)) ;; +let sources_without_pp t = + List.filter_map + [ t.source.files.intf; t.source.files.impl ] + ~f:(Option.map ~f:(fun (x : File.t) -> x.original_path)) +;; + module Obj_map = struct include Map.Make (struct type nonrec t = t @@ -387,7 +401,7 @@ let ml_source = | None -> f | Some suffix -> let path = Path.extend_basename f.path ~suffix in - File.make Dialect.ocaml path) + { f with dialect = Dialect.ocaml; path }) ;; let version_installed t ~src_root ~install_dir = diff --git a/src/dune_rules/module.mli b/src/dune_rules/module.mli index 7788038b68d..4e54bd91461 100644 --- a/src/dune_rules/module.mli +++ b/src/dune_rules/module.mli @@ -7,6 +7,7 @@ module File : sig val dialect : t -> Dialect.t val path : t -> Path.t + val original_path : t -> Path.t val make : Dialect.t -> Path.t -> t end @@ -61,7 +62,6 @@ val set_obj_name : t -> Module_name.Unique.t -> t val set_path : t -> Module_name.Path.t -> t val add_file : t -> Ml_kind.t -> File.t -> t val set_source : t -> Ml_kind.t -> File.t option -> t -val map_files : t -> f:(Ml_kind.t -> File.t -> File.t) -> t (** Set preprocessing flags *) val set_pp : t -> (string list Action_builder.t * Sandbox_config.t) option -> t @@ -88,6 +88,7 @@ module Obj_map : sig end val sources : t -> Path.t list +val sources_without_pp : t -> Path.t list val visibility : t -> Visibility.t val encode : t -> src_dir:Path.t -> Dune_lang.t list val decode : src_dir:Path.t -> t Dune_lang.Decoder.t diff --git a/test/blackbox-tests/test-cases/github2206.t/run.t b/test/blackbox-tests/test-cases/github2206.t/run.t index 2d0989b9469..976772d7dc0 100644 --- a/test/blackbox-tests/test-cases/github2206.t/run.t +++ b/test/blackbox-tests/test-cases/github2206.t/run.t @@ -5,3 +5,7 @@ copy_files would break the generation of the preprocessing flags (FLG (-pp $TESTCASE_ROOT/_build/default/pp.exe)) + -- + (FLG + (-pp + $TESTCASE_ROOT/_build/default/pp.exe)) diff --git a/test/blackbox-tests/test-cases/melange/merlin-compile-flags.t b/test/blackbox-tests/test-cases/melange/merlin-compile-flags.t index d6dc06619c2..3bd56c798ff 100644 --- a/test/blackbox-tests/test-cases/melange/merlin-compile-flags.t +++ b/test/blackbox-tests/test-cases/melange/merlin-compile-flags.t @@ -21,6 +21,9 @@ Show that the merlin config knows about melange.compile_flags +42))) +42))) +42))) + +42))) + +42))) + +42))) $ cat >dune < (melange.emit @@ -35,4 +38,7 @@ Show that the merlin config knows about melange.compile_flags +42))) +42))) +42))) + +42))) + +42))) + +42))) diff --git a/test/blackbox-tests/test-cases/melange/merlin.t b/test/blackbox-tests/test-cases/melange/merlin.t index 7002f53a1a6..8a4d7e6a873 100644 --- a/test/blackbox-tests/test-cases/melange/merlin.t +++ b/test/blackbox-tests/test-cases/melange/merlin.t @@ -25,11 +25,18 @@ $ dune ocaml merlin dump-config "$PWD" | grep -i "$lib" $TESTCASE_ROOT/_build/default/.foo.objs/melange) (FLG (-open Foo__)) + $TESTCASE_ROOT/_build/default/.foo.objs/melange) + (FLG (-open Foo__)) Foo: _build/default/foo $TESTCASE_ROOT/_build/default/.foo.objs/melange) (FLG (-open Foo__)) + Foo: _build/default/foo.ml + $TESTCASE_ROOT/_build/default/.foo.objs/melange) + (FLG (-open Foo__)) Foo__: _build/default/foo__ $TESTCASE_ROOT/_build/default/.foo.objs/melange) + Foo__: _build/default/foo__.ml-gen + $TESTCASE_ROOT/_build/default/.foo.objs/melange) Paths to Melange stdlib appear in B and S entries without melange.emit stanza @@ -54,6 +61,7 @@ Paths to Melange stdlib appear in B and S entries without melange.emit stanza $ dune build @check $ dune ocaml merlin dump-config $PWD | grep -i "$target" $TESTCASE_ROOT/_build/default/.output.mobjs/melange) + $TESTCASE_ROOT/_build/default/.output.mobjs/melange) Dump-dot-merlin includes the melange flags @@ -103,6 +111,28 @@ User ppx flags should appear in merlin config $ dune ocaml merlin dump-config $PWD | grep -v "(B " | grep -v "(S " Bar: _build/default/bar + ((STDLIB /MELC_STDLIB/melange) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.objs/melange) + (S + $TESTCASE_ROOT) + (FLG (-open Foo)) + (FLG + (-ppx + "$TESTCASE_ROOT/_build/default/.ppx/4128e43a9cfb141a37f547484cc9bf46/ppx.exe + --as-ppx + --cookie + 'library-name="foo"'")) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62@67@69-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) + Bar: _build/default/bar.ml ((STDLIB /MELC_STDLIB/melange) (EXCLUDE_QUERY_DIR) (B @@ -125,6 +155,27 @@ User ppx flags should appear in merlin config -keep-locs -g))) Foo: _build/default/foo + ((STDLIB /MELC_STDLIB/melange) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.objs/melange) + (S + $TESTCASE_ROOT) + (FLG + (-ppx + "$TESTCASE_ROOT/_build/default/.ppx/4128e43a9cfb141a37f547484cc9bf46/ppx.exe + --as-ppx + --cookie + 'library-name="foo"'")) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62@67@69-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) + Foo: _build/default/foo.ml-gen ((STDLIB /MELC_STDLIB/melange) (EXCLUDE_QUERY_DIR) (B @@ -160,3 +211,18 @@ User ppx flags should appear in merlin config -short-paths -keep-locs -g))) + Fooppx: _build/default/fooppx.ml + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.fooppx.objs/byte) + (S + $TESTCASE_ROOT) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62@67@69-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) diff --git a/test/blackbox-tests/test-cases/merlin/default-based-context.t/run.t b/test/blackbox-tests/test-cases/merlin/default-based-context.t/run.t index d29e5ee4eee..bab44db75f2 100644 --- a/test/blackbox-tests/test-cases/merlin/default-based-context.t/run.t +++ b/test/blackbox-tests/test-cases/merlin/default-based-context.t/run.t @@ -37,6 +37,21 @@ If Merlin field is absent, default context is chosen -short-paths -keep-locs -g))) + Foo: _build/default/foo.ml + ((STDLIB OPAM_PREFIX) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.objs/byte) + (S + $TESTCASE_ROOT) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) If Merlin field is present, this context is chosen @@ -75,3 +90,18 @@ If Merlin field is present, this context is chosen -short-paths -keep-locs -g))) + Foo: _build/cross/foo.ml + ((STDLIB OPAM_PREFIX) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/cross/.foo.objs/byte) + (S + $TESTCASE_ROOT) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) diff --git a/test/blackbox-tests/test-cases/merlin/dialect.t/dune-project b/test/blackbox-tests/test-cases/merlin/dialect.t/dune-project new file mode 100644 index 00000000000..1bf4647c9b4 --- /dev/null +++ b/test/blackbox-tests/test-cases/merlin/dialect.t/dune-project @@ -0,0 +1,10 @@ +(lang dune 3.16) + +(using melange 0.1) + +(dialect + (name mlx) + (implementation + (extension mlx) + (preprocess (run cat %{input-file})) + (merlin_reader mlx))) diff --git a/test/blackbox-tests/test-cases/merlin/dialect.t/exe/dune b/test/blackbox-tests/test-cases/merlin/dialect.t/exe/dune new file mode 100644 index 00000000000..efd40e79e08 --- /dev/null +++ b/test/blackbox-tests/test-cases/merlin/dialect.t/exe/dune @@ -0,0 +1,2 @@ +(executable + (name x)) diff --git a/test/blackbox-tests/test-cases/merlin/dialect.t/exe/x.mlx b/test/blackbox-tests/test-cases/merlin/dialect.t/exe/x.mlx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/blackbox-tests/test-cases/merlin/dialect.t/lib/dune b/test/blackbox-tests/test-cases/merlin/dialect.t/lib/dune new file mode 100644 index 00000000000..caefbf89753 --- /dev/null +++ b/test/blackbox-tests/test-cases/merlin/dialect.t/lib/dune @@ -0,0 +1,2 @@ +(library + (name x)) diff --git a/test/blackbox-tests/test-cases/merlin/dialect.t/lib/x.mlx b/test/blackbox-tests/test-cases/merlin/dialect.t/lib/x.mlx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/blackbox-tests/test-cases/merlin/dialect.t/melange/dune b/test/blackbox-tests/test-cases/merlin/dialect.t/melange/dune new file mode 100644 index 00000000000..e7804c2555b --- /dev/null +++ b/test/blackbox-tests/test-cases/merlin/dialect.t/melange/dune @@ -0,0 +1,3 @@ +(library + (modes melange) + (name x_mel)) diff --git a/test/blackbox-tests/test-cases/merlin/dialect.t/melange/x_mel.mlx b/test/blackbox-tests/test-cases/merlin/dialect.t/melange/x_mel.mlx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/blackbox-tests/test-cases/merlin/dialect.t/run.t b/test/blackbox-tests/test-cases/merlin/dialect.t/run.t new file mode 100644 index 00000000000..62106c4a9af --- /dev/null +++ b/test/blackbox-tests/test-cases/merlin/dialect.t/run.t @@ -0,0 +1,94 @@ + $ ocamlc_where="$(ocamlc -where)" + $ export BUILD_PATH_PREFIX_MAP="/OCAMLC_WHERE=$ocamlc_where:$BUILD_PATH_PREFIX_MAP" + $ ocamlfind_libs="$(ocamlfind printconf path | while read line; do printf lib=${line}:; done)" + $ export BUILD_PATH_PREFIX_MAP="$ocamlfind_libs:$BUILD_PATH_PREFIX_MAP" + $ melc_compiler="$(which melc)" + $ export BUILD_PATH_PREFIX_MAP="/MELC_COMPILER=$melc_compiler:$BUILD_PATH_PREFIX_MAP" + +CRAM sanitization + $ dune build ./exe/.merlin-conf/exe-x --profile release + $ dune ocaml merlin dump-config $PWD/exe + X: _build/default/exe/x + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/exe/.x.eobjs/byte) + (S + $TESTCASE_ROOT/exe) + (FLG (-w -40 -g)) + (SUFFIX ".mlx .mlx")) + X: _build/default/exe/x.mlx + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/exe/.x.eobjs/byte) + (S + $TESTCASE_ROOT/exe) + (FLG (-w -40 -g)) + (SUFFIX ".mlx .mlx") + (READER (mlx))) + X: _build/default/exe/x.mlx.mli + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/exe/.x.eobjs/byte) + (S + $TESTCASE_ROOT/exe) + (FLG (-w -40 -g)) + (SUFFIX ".mlx .mlx")) + +CRAM sanitization + $ dune build ./lib/.merlin-conf/lib-x --profile release + $ dune ocaml merlin dump-config $PWD/lib + X: _build/default/lib/x + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/lib/.x.objs/byte) + (S + $TESTCASE_ROOT/lib) + (FLG (-w -40 -g)) + (SUFFIX ".mlx .mlx") + (READER (mlx))) + X: _build/default/lib/x.mlx + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/lib/.x.objs/byte) + (S + $TESTCASE_ROOT/lib) + (FLG (-w -40 -g)) + (SUFFIX ".mlx .mlx") + (READER (mlx))) + +CRAM sanitization + $ dune build ./melange/.merlin-conf/lib-x_mel --profile release + $ dune ocaml merlin dump-config $PWD/melange + X_mel: _build/default/melange/x_mel + ((STDLIB lib/melange/melange) + (EXCLUDE_QUERY_DIR) + (B lib/melange/js/melange) + (B lib/melange/melange) + (B + $TESTCASE_ROOT/_build/default/melange/.x_mel.objs/melange) + (S lib/melange) + (S lib/melange/js) + (S + $TESTCASE_ROOT/melange) + (FLG (-w -40 -g)) + (SUFFIX ".mlx .mlx") + (READER (mlx))) + X_mel: _build/default/melange/x_mel.mlx + ((STDLIB lib/melange/melange) + (EXCLUDE_QUERY_DIR) + (B lib/melange/js/melange) + (B lib/melange/melange) + (B + $TESTCASE_ROOT/_build/default/melange/.x_mel.objs/melange) + (S lib/melange) + (S lib/melange/js) + (S + $TESTCASE_ROOT/melange) + (FLG (-w -40 -g)) + (SUFFIX ".mlx .mlx") + (READER (mlx))) diff --git a/test/blackbox-tests/test-cases/merlin/future-syntax.t b/test/blackbox-tests/test-cases/merlin/future-syntax.t index c9aa4119907..c70ccca2e6f 100644 --- a/test/blackbox-tests/test-cases/merlin/future-syntax.t +++ b/test/blackbox-tests/test-cases/merlin/future-syntax.t @@ -25,3 +25,19 @@ (S $TESTCASE_ROOT) (FLG (-w -40 -g))) + Pp_future_syntax: _build/default/pp_future_syntax.ml + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.pp_future_syntax.eobjs/byte) + (S + $TESTCASE_ROOT) + (FLG (-w -40 -g))) + Pp_future_syntax: _build/default/pp_future_syntax.mli + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.pp_future_syntax.eobjs/byte) + (S + $TESTCASE_ROOT) + (FLG (-w -40 -g))) diff --git a/test/blackbox-tests/test-cases/merlin/github1946.t/run.t b/test/blackbox-tests/test-cases/merlin/github1946.t/run.t index 248f27088e9..ffa28575f75 100644 --- a/test/blackbox-tests/test-cases/merlin/github1946.t/run.t +++ b/test/blackbox-tests/test-cases/merlin/github1946.t/run.t @@ -7,6 +7,20 @@ in the same dune file, but require different ppx specifications $ dune build @all --profile release $ dune ocaml merlin dump-config $PWD Usesppx1: _build/default/usesppx1 + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.usesppx1.objs/byte) + (S + $TESTCASE_ROOT) + (FLG + (-ppx + "$TESTCASE_ROOT/_build/default/.ppx/c152d6ca3c7e1d83471ffdf48bf729ae/ppx.exe + --as-ppx + --cookie + 'library-name="usesppx1"'")) + (FLG (-w -40 -g))) + Usesppx1: _build/default/usesppx1.ml-gen ((STDLIB /OCAMLC_WHERE) (EXCLUDE_QUERY_DIR) (B @@ -34,3 +48,17 @@ in the same dune file, but require different ppx specifications --cookie 'library-name="usesppx2"'")) (FLG (-w -40 -g))) + Usesppx2: _build/default/usesppx2.ml-gen + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.usesppx2.objs/byte) + (S + $TESTCASE_ROOT) + (FLG + (-ppx + "$TESTCASE_ROOT/_build/default/.ppx/d7394c27c5e0f7ad7ab1110d6b092c05/ppx.exe + --as-ppx + --cookie + 'library-name="usesppx2"'")) + (FLG (-w -40 -g))) diff --git a/test/blackbox-tests/test-cases/merlin/github4125.t/run.t b/test/blackbox-tests/test-cases/merlin/github4125.t/run.t index 05645739523..39b8b2fd915 100644 --- a/test/blackbox-tests/test-cases/merlin/github4125.t/run.t +++ b/test/blackbox-tests/test-cases/merlin/github4125.t/run.t @@ -37,3 +37,18 @@ We call `$(opam switch show)` so that this test always uses an existing switch -short-paths -keep-locs -g))) + Foo: _build/cross/foo.ml + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/cross/.foo.objs/byte) + (S + $TESTCASE_ROOT) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) diff --git a/test/blackbox-tests/test-cases/merlin/github759.t/run.t b/test/blackbox-tests/test-cases/merlin/github759.t/run.t index d9c548a4a03..286f4180c8b 100644 --- a/test/blackbox-tests/test-cases/merlin/github759.t/run.t +++ b/test/blackbox-tests/test-cases/merlin/github759.t/run.t @@ -4,6 +4,14 @@ $ dune build foo.cma --profile release $ dune ocaml merlin dump-config $PWD Foo: _build/default/foo + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.objs/byte) + (S + $TESTCASE_ROOT) + (FLG (-w -40 -g))) + Foo: _build/default/foo.ml-gen ((STDLIB /OCAMLC_WHERE) (EXCLUDE_QUERY_DIR) (B @@ -16,6 +24,14 @@ $ dune build foo.cma --profile release $ dune ocaml merlin dump-config $PWD Foo: _build/default/foo + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.objs/byte) + (S + $TESTCASE_ROOT) + (FLG (-w -40 -g))) + Foo: _build/default/foo.ml-gen ((STDLIB /OCAMLC_WHERE) (EXCLUDE_QUERY_DIR) (B @@ -35,3 +51,11 @@ (S $TESTCASE_ROOT) (FLG (-w -40 -g))) + Foo: _build/default/foo.ml-gen + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.objs/byte) + (S + $TESTCASE_ROOT) + (FLG (-w -40 -g))) diff --git a/test/blackbox-tests/test-cases/merlin/granularity.t b/test/blackbox-tests/test-cases/merlin/granularity.t new file mode 100644 index 00000000000..ec8bdb63cd1 --- /dev/null +++ b/test/blackbox-tests/test-cases/merlin/granularity.t @@ -0,0 +1,213 @@ + $ ocamlc_where="$(ocamlc -where)" + $ export BUILD_PATH_PREFIX_MAP="/OCAMLC_WHERE=$ocamlc_where:$BUILD_PATH_PREFIX_MAP" + +A utility to query merlin configuration for a file: + $ cat >merlin_conf.sh < #!/bin/sh + > FILE=\$1 + > printf "(4:File%d:%s)" \${#FILE} \$FILE | dune ocaml-merlin \ + > | sed -E "s/[[:digit:]]+:/\?:/g" | sed -E "s/\)(\(+)/\n\1/g" + > EOF + + $ chmod a+x merlin_conf.sh + +Project sources + + $ cat >dune-project < (lang dune 3.16) + > (using melange 0.1) + > + > (dialect + > (name mlx) + > (implementation + > (extension mlx) + > (preprocess (run cat %{input-file})) + > (merlin_reader mlx))) + > EOF + + $ cat >pp.sh < #!/bin/sh + > sed 's/%INT%/42/g' \$1 + > EOF + + $ chmod a+x pp.sh + + $ cat >dune < (executable + > (name test) + > (flags :standard -no-strict-formats) + > (preprocess + > (per_module + > ((action (run ./pp.sh %{input-file})) pped)))) + > + > (rule + > (action (copy cppomod.cppo.ml cppomod.ml))) + > + > (rule + > (action (copy wrongext.cppo.cml wrongext.ml))) + > + > (rule + > (target generatedx.mlx) + > (mode promote) + > (action (with-stdout-to %{target} (echo "let x = \"Generatedx!\"")))) + > + > (rule + > (target generated.ml) + > (mode promote) + > (action (with-stdout-to %{target} (echo "let x = \"Generated!\"")))) + > EOF + + $ cat >test.ml < print_endline Pped.x_42;; + > print_endline Mel.x;; + > print_endline Cppomod.x;; + > print_endline Wrongext.x;; + > print_endline Generated.x;; + > EOF + +Both Pped's ml and mli files will be preprocessed + $ cat >pped.mli < val x_%INT% : string + > EOF + + $ cat >pped.ml < let x_42 = "%INT%" + > EOF + +Melange module signature + $ cat >mel.mli < val x : string + > EOF + +Melange module implementation in Melange syntax + $ cat >mel.mlx < let x = "43" + > EOF + +A pped file with unconventionnal filename + $ cat >cppomod.cppo.ml < let x = "44" + > EOF + + $ cat >wrongext.cppo.cml < let x = "45" + > EOF + + $ dune build @check + $ dune exec ./test.exe + 42 + 43 + 44 + 45 + Generated! + +We now query Merlin configuration for the various source files: + +Some configuration fields are common to all the modules of a same stanza. This +is the case for the stdlib, build and sources directories, flags and suffixes. + +Some configuration can be specific to a module like preprocessing. + +Dialects are specified by extensions so are specific to a file. This means a +different reader might be used for the signature and the implementation. + +Note that Merlin should always be told about dialect-provided suffixes, to make `MerlinLocate` work correctly. + +Preprocessing: + +Is it expected that the suffix for implementation and interface is the same ? + $ ./merlin_conf.sh pped.ml | tee pped.out + ((?:STDLIB?:/OCAMLC_WHERE + (?:EXCLUDE_QUERY_DIR + (?:B?:$TESTCASE_ROOT/_build/default/.test.eobjs/byte + (?:S?:$TESTCASE_ROOT + (?:FLG(?:-open?:Dune__exe) + (?:FLG(?:-pp?:$TESTCASE_ROOT/_build/default/pp.sh) + (?:FLG(?:-w?:@1..3@5..28@31..39@43@46..47@49..57@61..62@67@69-?:-strict-sequence?:-strict-formats?:-short-paths?:-keep-locs?:-no-strict-formats?:-g) + (?:SUFFIX?:.mlx .mlx)) + + $ ./merlin_conf.sh pped.mli | diff pped.out - + +Melange: + +As expected, the reader is not communicated for the standard mli + $ ./merlin_conf.sh mel.mli | tee mel.out + ((?:STDLIB?:/OCAMLC_WHERE + (?:EXCLUDE_QUERY_DIR + (?:B?:$TESTCASE_ROOT/_build/default/.test.eobjs/byte + (?:S?:$TESTCASE_ROOT + (?:FLG(?:-open?:Dune__exe) + (?:FLG(?:-w?:@1..3@5..28@31..39@43@46..47@49..57@61..62@67@69-?:-strict-sequence?:-strict-formats?:-short-paths?:-keep-locs?:-no-strict-formats?:-g) + (?:SUFFIX?:.mlx .mlx)) + +The reader is set for the mlx file + $ ./merlin_conf.sh mel.mlx | diff mel.out - + 7c7,8 + < (?:SUFFIX?:.mlx .mlx)) + \ No newline at end of file + --- + > (?:SUFFIX?:.mlx .mlx + > (?:READER(?:mlx))) + \ No newline at end of file + [1] + +Unconventional file names: + +Users might have preprocessing steps that start with a non-conventional +filename like `mymodule.cppo.ml`. + +While Dune first tries to match by the exact filename requested, if nothing is +found, then it'll make a guess that the file was preprocessed into a file with +.ml extension: + + $ ./merlin_conf.sh cppomod.cppo.ml | tee cppomod.out + ((?:STDLIB?:/OCAMLC_WHERE + (?:EXCLUDE_QUERY_DIR + (?:B?:$TESTCASE_ROOT/_build/default/.test.eobjs/byte + (?:S?:$TESTCASE_ROOT + (?:FLG(?:-open?:Dune__exe) + (?:FLG(?:-w?:@1..3@5..28@31..39@43@46..47@49..57@61..62@67@69-?:-strict-sequence?:-strict-formats?:-short-paths?:-keep-locs?:-no-strict-formats?:-g) + (?:SUFFIX?:.mlx .mlx)) + + $ ./merlin_conf.sh cppomod.ml | diff cppomod.out - + +Note that this means unrelated files might be given the same configuration: + + $ ./merlin_conf.sh cppomod.tralala.ml | diff cppomod.out - + +And with unconventional extension: +(note that without appropriate suffix configuration Merlin will never jump to +such files) +We could expect dune to get the wrongext module configuration + $ ./merlin_conf.sh wrongext.cppo.cml | tee wrongext.out + ((?:STDLIB?:/OCAMLC_WHERE + (?:EXCLUDE_QUERY_DIR + (?:B?:$TESTCASE_ROOT/_build/default/.test.eobjs/byte + (?:S?:$TESTCASE_ROOT + (?:FLG(?:-open?:Dune__exe) + (?:FLG(?:-w?:@1..3@5..28@31..39@43@46..47@49..57@61..62@67@69-?:-strict-sequence?:-strict-formats?:-short-paths?:-keep-locs?:-no-strict-formats?:-g) + (?:SUFFIX?:.mlx .mlx)) + +We also have generated.ml and generatedx.mlx promoted: + $ ls -1 . | grep generated + generated.ml + generatedx.mlx + +It should be possible to get its merlin configuration as well: + $ ./merlin_conf.sh generated.ml + ((?:STDLIB?:/OCAMLC_WHERE + (?:EXCLUDE_QUERY_DIR + (?:B?:$TESTCASE_ROOT/_build/default/.test.eobjs/byte + (?:S?:$TESTCASE_ROOT + (?:FLG(?:-open?:Dune__exe) + (?:FLG(?:-w?:@1..3@5..28@31..39@43@46..47@49..57@61..62@67@69-?:-strict-sequence?:-strict-formats?:-short-paths?:-keep-locs?:-no-strict-formats?:-g) + (?:SUFFIX?:.mlx .mlx)) + $ ./merlin_conf.sh generatedx.mlx + ((?:STDLIB?:/OCAMLC_WHERE + (?:EXCLUDE_QUERY_DIR + (?:B?:$TESTCASE_ROOT/_build/default/.test.eobjs/byte + (?:S?:$TESTCASE_ROOT + (?:FLG(?:-open?:Dune__exe) + (?:FLG(?:-w?:@1..3@5..28@31..39@43@46..47@49..57@61..62@67@69-?:-strict-sequence?:-strict-formats?:-short-paths?:-keep-locs?:-no-strict-formats?:-g) + (?:SUFFIX?:.mlx .mlx + (?:READER(?:mlx))) diff --git a/test/blackbox-tests/test-cases/merlin/include-subdirs-qualified.t b/test/blackbox-tests/test-cases/merlin/include-subdirs-qualified.t index 9a1847ad0ac..834f28c3694 100644 --- a/test/blackbox-tests/test-cases/merlin/include-subdirs-qualified.t +++ b/test/blackbox-tests/test-cases/merlin/include-subdirs-qualified.t @@ -22,6 +22,25 @@ $ dune build .merlin-conf/lib-foo $ dune ocaml merlin dump-config . Foo: _build/default/foo + ((STDLIB /OPAM_PREFIX) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.objs/byte) + (S + $TESTCASE_ROOT) + (S + $TESTCASE_ROOT/groupintf) + (S + $TESTCASE_ROOT/utils) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62@67@69-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) + Foo: _build/default/foo.ml-gen ((STDLIB /OPAM_PREFIX) (EXCLUDE_QUERY_DIR) (B @@ -41,6 +60,25 @@ -keep-locs -g))) Foo__Groupintf__: _build/default/foo__Groupintf__ + ((STDLIB /OPAM_PREFIX) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.objs/byte) + (S + $TESTCASE_ROOT) + (S + $TESTCASE_ROOT/groupintf) + (S + $TESTCASE_ROOT/utils) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62@67@69-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) + Foo__Groupintf__: _build/default/foo__Groupintf__.ml-gen ((STDLIB /OPAM_PREFIX) (EXCLUDE_QUERY_DIR) (B @@ -60,6 +98,25 @@ -keep-locs -g))) Utils: _build/default/foo__Utils + ((STDLIB /OPAM_PREFIX) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.objs/byte) + (S + $TESTCASE_ROOT) + (S + $TESTCASE_ROOT/groupintf) + (S + $TESTCASE_ROOT/utils) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62@67@69-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) + Utils: _build/default/foo__Utils.ml-gen ((STDLIB /OPAM_PREFIX) (EXCLUDE_QUERY_DIR) (B @@ -79,6 +136,26 @@ -keep-locs -g))) Calc: _build/default/groupintf/calc + ((STDLIB /OPAM_PREFIX) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.objs/byte) + (S + $TESTCASE_ROOT) + (S + $TESTCASE_ROOT/groupintf) + (S + $TESTCASE_ROOT/utils) + (FLG (-open Foo__Groupintf__ -open Foo)) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62@67@69-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) + Calc: _build/default/groupintf/calc.ml ((STDLIB /OPAM_PREFIX) (EXCLUDE_QUERY_DIR) (B @@ -99,6 +176,26 @@ -keep-locs -g))) Groupintf: _build/default/groupintf/groupintf + ((STDLIB /OPAM_PREFIX) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.objs/byte) + (S + $TESTCASE_ROOT) + (S + $TESTCASE_ROOT/groupintf) + (S + $TESTCASE_ROOT/utils) + (FLG (-open Foo__Groupintf__ -open Foo)) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62@67@69-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) + Groupintf: _build/default/groupintf/groupintf.ml ((STDLIB /OPAM_PREFIX) (EXCLUDE_QUERY_DIR) (B @@ -119,6 +216,26 @@ -keep-locs -g))) Main: _build/default/main + ((STDLIB /OPAM_PREFIX) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.objs/byte) + (S + $TESTCASE_ROOT) + (S + $TESTCASE_ROOT/groupintf) + (S + $TESTCASE_ROOT/utils) + (FLG (-open Foo)) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62@67@69-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) + Main: _build/default/main.ml ((STDLIB /OPAM_PREFIX) (EXCLUDE_QUERY_DIR) (B @@ -139,6 +256,26 @@ -keep-locs -g))) Calc: _build/default/utils/calc + ((STDLIB /OPAM_PREFIX) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.objs/byte) + (S + $TESTCASE_ROOT) + (S + $TESTCASE_ROOT/groupintf) + (S + $TESTCASE_ROOT/utils) + (FLG (-open Foo__Utils -open Foo)) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62@67@69-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) + Calc: _build/default/utils/calc.ml ((STDLIB /OPAM_PREFIX) (EXCLUDE_QUERY_DIR) (B diff --git a/test/blackbox-tests/test-cases/merlin/instrumentation.t/run.t b/test/blackbox-tests/test-cases/merlin/instrumentation.t/run.t index 7a94d814404..2fea5f64a9f 100644 --- a/test/blackbox-tests/test-cases/merlin/instrumentation.t/run.t +++ b/test/blackbox-tests/test-cases/merlin/instrumentation.t/run.t @@ -9,6 +9,20 @@ up a project with instrumentation and testing checking the merlin config. $ dune build --instrument-with hello ./lib/.merlin-conf/lib-foo ./lib/.merlin-conf/lib-bar --profile release $ dune ocaml merlin dump-config $PWD/lib Bar: _build/default/lib/bar + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/lib/.bar.objs/byte) + (B + $TESTCASE_ROOT/_build/default/ppx/.hello.objs/byte) + (S + $TESTCASE_ROOT/lib) + (S + $TESTCASE_ROOT/lib/subdir) + (S + $TESTCASE_ROOT/ppx) + (FLG (-w -40 -g))) + Bar: _build/default/lib/bar.ml-gen ((STDLIB /OCAMLC_WHERE) (EXCLUDE_QUERY_DIR) (B @@ -23,6 +37,21 @@ up a project with instrumentation and testing checking the merlin config. $TESTCASE_ROOT/ppx) (FLG (-w -40 -g))) File: _build/default/lib/subdir/file + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/lib/.bar.objs/byte) + (B + $TESTCASE_ROOT/_build/default/ppx/.hello.objs/byte) + (S + $TESTCASE_ROOT/lib) + (S + $TESTCASE_ROOT/lib/subdir) + (S + $TESTCASE_ROOT/ppx) + (FLG (-open Bar)) + (FLG (-w -40 -g))) + File: _build/default/lib/subdir/file.ml ((STDLIB /OCAMLC_WHERE) (EXCLUDE_QUERY_DIR) (B @@ -38,6 +67,20 @@ up a project with instrumentation and testing checking the merlin config. (FLG (-open Bar)) (FLG (-w -40 -g))) Foo: _build/default/lib/foo + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/lib/.foo.objs/byte) + (B + $TESTCASE_ROOT/_build/default/ppx/.hello.objs/byte) + (S + $TESTCASE_ROOT/lib) + (S + $TESTCASE_ROOT/lib/subdir) + (S + $TESTCASE_ROOT/ppx) + (FLG (-w -40 -g))) + Foo: _build/default/lib/foo.ml-gen ((STDLIB /OCAMLC_WHERE) (EXCLUDE_QUERY_DIR) (B @@ -66,3 +109,18 @@ up a project with instrumentation and testing checking the merlin config. $TESTCASE_ROOT/ppx) (FLG (-open Foo)) (FLG (-w -40 -g))) + Privmod: _build/default/lib/privmod.ml + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/lib/.foo.objs/byte) + (B + $TESTCASE_ROOT/_build/default/ppx/.hello.objs/byte) + (S + $TESTCASE_ROOT/lib) + (S + $TESTCASE_ROOT/lib/subdir) + (S + $TESTCASE_ROOT/ppx) + (FLG (-open Foo)) + (FLG (-w -40 -g))) diff --git a/test/blackbox-tests/test-cases/merlin/merlin-from-subdir.t/run.t b/test/blackbox-tests/test-cases/merlin/merlin-from-subdir.t/run.t index b3aab326d86..3895364d430 100644 --- a/test/blackbox-tests/test-cases/merlin/merlin-from-subdir.t/run.t +++ b/test/blackbox-tests/test-cases/merlin/merlin-from-subdir.t/run.t @@ -8,6 +8,25 @@ We build the project Verify that merlin configuration was generated... $ dune ocaml merlin dump-config $PWD Test: _build/default/test + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.objs/byte) + (B + $TESTCASE_ROOT/_build/default/.test.eobjs/byte) + (S + $TESTCASE_ROOT) + (S + $TESTCASE_ROOT/411) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) + Test: _build/default/test.ml ((STDLIB /OCAMLC_WHERE) (EXCLUDE_QUERY_DIR) (B @@ -43,6 +62,23 @@ Verify that merlin configuration was generated... -short-paths -keep-locs -g))) + Foo: _build/default/foo.ml + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.objs/byte) + (S + $TESTCASE_ROOT) + (S + $TESTCASE_ROOT/411) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) ...but not in the sub-folder whose content was copied $ dune ocaml merlin dump-config $PWD/411 diff --git a/test/blackbox-tests/test-cases/merlin/merlin-tests.t/run.t b/test/blackbox-tests/test-cases/merlin/merlin-tests.t/run.t index ed506bb77df..c164517d918 100644 --- a/test/blackbox-tests/test-cases/merlin/merlin-tests.t/run.t +++ b/test/blackbox-tests/test-cases/merlin/merlin-tests.t/run.t @@ -14,6 +14,25 @@ CRAM sanitization $ dune build ./exe/.merlin-conf/exe-x --profile release $ dune ocaml merlin dump-config $PWD/exe X: _build/default/exe/x + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_findlib/publicfoo) + (B + $TESTCASE_ROOT/_build/default/exe/.x.eobjs/byte) + (B + $TESTCASE_ROOT/_build/default/lib/.foo.objs/public_cmi) + (S + $TESTCASE_ROOT/_findlib/publicfoo) + (S + $TESTCASE_ROOT/exe) + (S + $TESTCASE_ROOT/lib) + (FLG + (-pp + $TESTCASE_ROOT/_build/default/pp/pp.exe)) + (FLG (-w -40 -g))) + X: _build/default/exe/x.ml ((STDLIB /OCAMLC_WHERE) (EXCLUDE_QUERY_DIR) (B @@ -36,6 +55,22 @@ CRAM sanitization $ dune build ./lib/.merlin-conf/lib-foo ./lib/.merlin-conf/lib-bar --profile release $ dune ocaml merlin dump-config $PWD/lib Bar: _build/default/lib/bar + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/lib/.bar.objs/byte) + (S + $TESTCASE_ROOT/lib) + (S + $TESTCASE_ROOT/lib/subdir) + (FLG + (-ppx + "$TESTCASE_ROOT/_build/default/.ppx/4128e43a9cfb141a37f547484cc9bf46/ppx.exe + --as-ppx + --cookie + 'library-name="bar"'")) + (FLG (-w -40 -g))) + Bar: _build/default/lib/bar.ml-gen ((STDLIB /OCAMLC_WHERE) (EXCLUDE_QUERY_DIR) (B @@ -52,6 +87,23 @@ CRAM sanitization 'library-name="bar"'")) (FLG (-w -40 -g))) File: _build/default/lib/subdir/file + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/lib/.bar.objs/byte) + (S + $TESTCASE_ROOT/lib) + (S + $TESTCASE_ROOT/lib/subdir) + (FLG (-open Bar)) + (FLG + (-ppx + "$TESTCASE_ROOT/_build/default/.ppx/4128e43a9cfb141a37f547484cc9bf46/ppx.exe + --as-ppx + --cookie + 'library-name="bar"'")) + (FLG (-w -40 -g))) + File: _build/default/lib/subdir/file.ml ((STDLIB /OCAMLC_WHERE) (EXCLUDE_QUERY_DIR) (B @@ -69,6 +121,26 @@ CRAM sanitization 'library-name="bar"'")) (FLG (-w -40 -g))) Foo: _build/default/lib/foo + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_findlib/publicfoo) + (B + $TESTCASE_ROOT/_build/default/lib/.foo.objs/byte) + (S + $TESTCASE_ROOT/_findlib/publicfoo) + (S + $TESTCASE_ROOT/lib) + (S + $TESTCASE_ROOT/lib/subdir) + (FLG + (-ppx + "$TESTCASE_ROOT/_build/default/.ppx/4128e43a9cfb141a37f547484cc9bf46/ppx.exe + --as-ppx + --cookie + 'library-name="foo"'")) + (FLG (-w -40 -g))) + Foo: _build/default/lib/foo.ml-gen ((STDLIB /OCAMLC_WHERE) (EXCLUDE_QUERY_DIR) (B @@ -109,6 +181,27 @@ CRAM sanitization --cookie 'library-name="foo"'")) (FLG (-w -40 -g))) + Privmod: _build/default/lib/privmod.ml + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_findlib/publicfoo) + (B + $TESTCASE_ROOT/_build/default/lib/.foo.objs/byte) + (S + $TESTCASE_ROOT/_findlib/publicfoo) + (S + $TESTCASE_ROOT/lib) + (S + $TESTCASE_ROOT/lib/subdir) + (FLG (-open Foo)) + (FLG + (-ppx + "$TESTCASE_ROOT/_build/default/.ppx/4128e43a9cfb141a37f547484cc9bf46/ppx.exe + --as-ppx + --cookie + 'library-name="foo"'")) + (FLG (-w -40 -g))) Make sure a ppx directive is generated (if not, the [grep ppx] step fails) $ dune ocaml merlin dump-config $PWD/lib | grep ppx > /dev/null @@ -129,11 +222,38 @@ Make sure pp flag is correct and variables are expanded "$TESTCASE_ROOT/_build/default/pp/pp.exe -nothing")) (FLG (-w -40 -g))) + Foobar: _build/default/pp-with-expand/foobar.ml + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/pp-with-expand/.foobar.eobjs/byte) + (S + $TESTCASE_ROOT/pp-with-expand) + (FLG + (-pp + "$TESTCASE_ROOT/_build/default/pp/pp.exe + -nothing")) + (FLG (-w -40 -g))) Check hash of executables names if more than one $ dune build ./exes/.merlin-conf/exe-x-6562915302827c6dce0630390bfa68b7 $ dune ocaml merlin dump-config $PWD/exes X: _build/default/exes/x + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/exes/.x.eobjs/byte) + (S + $TESTCASE_ROOT/exes) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) + X: _build/default/exes/x.ml ((STDLIB /OCAMLC_WHERE) (EXCLUDE_QUERY_DIR) (B @@ -163,3 +283,18 @@ Check hash of executables names if more than one -short-paths -keep-locs -g))) + Y: _build/default/exes/y.ml + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/exes/.x.eobjs/byte) + (S + $TESTCASE_ROOT/exes) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) diff --git a/test/blackbox-tests/test-cases/merlin/per-module-pp.t/run.t b/test/blackbox-tests/test-cases/merlin/per-module-pp.t/run.t index bc757674273..532a2f258a7 100644 --- a/test/blackbox-tests/test-cases/merlin/per-module-pp.t/run.t +++ b/test/blackbox-tests/test-cases/merlin/per-module-pp.t/run.t @@ -8,6 +8,21 @@ should appear only once since only Foo is using it. $ dune ocaml merlin dump-config $PWD Bar: _build/default/bar + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.objs/byte) + (S + $TESTCASE_ROOT) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) + Bar: _build/default/bar.ml ((STDLIB /OCAMLC_WHERE) (EXCLUDE_QUERY_DIR) (B @@ -40,3 +55,21 @@ should appear only once since only Foo is using it. -short-paths -keep-locs -g))) + Foo: _build/default/foo.ml + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.objs/byte) + (S + $TESTCASE_ROOT) + (FLG + (-pp + $TESTCASE_ROOT/_build/default/pp/pp.exe)) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) diff --git a/test/blackbox-tests/test-cases/merlin/src-dirs-of-deps.t b/test/blackbox-tests/test-cases/merlin/src-dirs-of-deps.t index 9b5eb4152a5..178fccc1c7b 100644 --- a/test/blackbox-tests/test-cases/merlin/src-dirs-of-deps.t +++ b/test/blackbox-tests/test-cases/merlin/src-dirs-of-deps.t @@ -43,3 +43,24 @@ library also has more than one src dir. -short-paths -keep-locs -g))) + Lib2: _build/default/lib2/lib2.ml-gen + ((STDLIB /OPAM_PREFIX) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/lib1/.lib1.objs/byte) + (B + $TESTCASE_ROOT/_build/default/lib2/.lib2.objs/byte) + (S + $TESTCASE_ROOT/lib1) + (S + $TESTCASE_ROOT/lib1/sub) + (S + $TESTCASE_ROOT/lib2) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) diff --git a/test/blackbox-tests/test-cases/merlin/suffix.t/run.t b/test/blackbox-tests/test-cases/merlin/suffix.t/run.t index 159ba87fd27..9e3e0002406 100644 --- a/test/blackbox-tests/test-cases/merlin/suffix.t/run.t +++ b/test/blackbox-tests/test-cases/merlin/suffix.t/run.t @@ -3,3 +3,5 @@ $ dune ocaml merlin dump-config $PWD | grep SUFFIX (SUFFIX ".aml .amli") (SUFFIX ".baml .bamli")) + (SUFFIX ".aml .amli") + (SUFFIX ".baml .bamli")) diff --git a/test/blackbox-tests/test-cases/merlin/unit-names-merlin-gh1233.t/run.t b/test/blackbox-tests/test-cases/merlin/unit-names-merlin-gh1233.t/run.t index 80e7b75a08b..0a181e434b2 100644 --- a/test/blackbox-tests/test-cases/merlin/unit-names-merlin-gh1233.t/run.t +++ b/test/blackbox-tests/test-cases/merlin/unit-names-merlin-gh1233.t/run.t @@ -6,6 +6,25 @@ $ dune ocaml merlin dump-config $PWD Foo: _build/default/foo + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/.foo.eobjs/byte) + (B + $TESTCASE_ROOT/_build/default/foo/.foo.objs/byte) + (S + $TESTCASE_ROOT) + (S + $TESTCASE_ROOT/foo) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) + Foo: _build/default/foo.ml ((STDLIB /OCAMLC_WHERE) (EXCLUDE_QUERY_DIR) (B @@ -27,6 +46,22 @@ $ dune ocaml merlin dump-config $PWD/foo Bar: _build/default/foo/bar + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/foo/.foo.objs/byte) + (S + $TESTCASE_ROOT/foo) + (FLG (-open Foo)) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) + Bar: _build/default/foo/bar.ml ((STDLIB /OCAMLC_WHERE) (EXCLUDE_QUERY_DIR) (B @@ -57,6 +92,21 @@ -short-paths -keep-locs -g))) + Foo: _build/default/foo/foo.ml-gen + ((STDLIB /OCAMLC_WHERE) + (EXCLUDE_QUERY_DIR) + (B + $TESTCASE_ROOT/_build/default/foo/.foo.objs/byte) + (S + $TESTCASE_ROOT/foo) + (FLG + (-w + @1..3@5..28@30..39@43@46..47@49..57@61..62-40 + -strict-sequence + -strict-formats + -short-paths + -keep-locs + -g))) FIXME : module Foo is not unbound This test is disabled because it depends on root detection and is not reproducible.