Skip to content

Commit 6955c2e

Browse files
committed
test(single-context): generate mode-aware Merlin configs
Signed-off-by: Antonio Nuno Monteiro <anmonteiro@gmail.com>
1 parent 9215798 commit 6955c2e

5 files changed

Lines changed: 144 additions & 31 deletions

File tree

src/dune_rules/gen_rules.ml

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,11 @@ end = struct
6060
; source_dirs : 'source_dirs
6161
}
6262

63-
let empty_none = { merlin = None; cctx = None; js = None; source_dirs = None }
63+
let empty_none = { merlin = []; cctx = []; js = None; source_dirs = None }
6464
let empty_list = { merlin = []; cctx = Loc.Map.empty; js = []; source_dirs = [] }
6565

66-
let add_map_maybe hd_o tl =
67-
match hd_o with
68-
| Some (loc, hd) ->
66+
let add_map hds tl =
67+
List.fold_left hds ~init:tl ~f:(fun tl (loc, hd) ->
6968
Loc.Map.update tl loc ~f:(function
7069
| None ->
7170
Some
@@ -78,20 +77,16 @@ end = struct
7877
(Compilation_mode.By_mode.of_list
7978
~init:None
8079
((Compilation_context.for_ hd, Some hd)
81-
:: List.map current ~f:(fun (k, v) -> k, Some v))))
82-
| None -> tl
83-
;;
84-
85-
let cons_maybe hd_o tl =
86-
match hd_o with
87-
| Some hd -> hd :: tl
88-
| None -> tl
80+
:: List.map current ~f:(fun (k, v) -> k, Some v)))))
8981
;;
9082

9183
let cons acc x =
92-
{ merlin = cons_maybe x.merlin acc.merlin
93-
; cctx = add_map_maybe x.cctx acc.cctx
94-
; source_dirs = cons_maybe x.source_dirs acc.source_dirs
84+
{ merlin = List.rev_append x.merlin acc.merlin
85+
; cctx = add_map x.cctx acc.cctx
86+
; source_dirs =
87+
(match x.source_dirs with
88+
| None -> acc.source_dirs
89+
| Some source_dir -> source_dir :: acc.source_dirs)
9590
; js =
9691
(match x.js with
9792
| None -> acc.js
@@ -107,7 +102,7 @@ end = struct
107102
;;
108103

109104
let with_cctx_merlin ~loc (cctx, merlin) =
110-
{ empty_none with merlin = Some merlin; cctx = Some (loc, cctx) }
105+
{ empty_none with merlin = [ merlin ]; cctx = [ loc, cctx ] }
111106
;;
112107

113108
let if_available_buildable ~loc f = function
@@ -129,12 +124,16 @@ end = struct
129124
(Scope.libs scope)
130125
(Local (Library.to_lib_id ~src_dir lib))
131126
in
132-
if_available_buildable
133-
~loc:lib.buildable.loc
127+
if_available
134128
(fun () ->
135-
Lib_rules.rules lib ~sctx ~scope ~dir_contents ~expander
136-
>>| Compilation_mode.By_mode.choose
137-
>>| Option.value_exn)
129+
let+ cctx_merlins = Lib_rules.rules lib ~sctx ~scope ~dir_contents ~expander in
130+
let cctx_merlins =
131+
Compilation_mode.By_mode.to_list cctx_merlins |> List.map ~f:snd
132+
in
133+
{ empty_none with
134+
merlin = List.map cctx_merlins ~f:snd
135+
; cctx = List.map cctx_merlins ~f:(fun (cctx, _) -> lib.buildable.loc, cctx)
136+
})
138137
enabled_if
139138
| Foreign_library.T lib ->
140139
Expander.eval_blang expander lib.enabled_if

src/dune_rules/lib_rules.ml

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,7 @@ let library_rules
551551
~compile_info
552552
~ctx_dir
553553
~for_merlin
554+
~merlin_ident
554555
=
555556
let modules = Compilation_context.modules cctx in
556557
let obj_dir = Compilation_context.obj_dir cctx in
@@ -640,18 +641,22 @@ let library_rules
640641
let+ requires_hidden = Compilation_context.requires_hidden cctx
641642
and+ parameters = Compilation_context.parameters cctx in
642643
let flags = Compilation_context.flags cctx in
644+
let preprocess =
645+
match for_ with
646+
| Ocaml -> lib.buildable.preprocess.config
647+
| Melange -> lib.buildable.melange_preprocess.config
648+
in
643649
Merlin.make
644650
~requires_compile
645651
~requires_hidden
646652
~stdlib_dir:lib_config.stdlib_dir
647653
~flags
648654
~modules
649-
~preprocess:
650-
(Preprocess.Per_module.without_instrumentation lib.buildable.preprocess.config)
655+
~preprocess:(Preprocess.Per_module.without_instrumentation preprocess)
651656
~libname:(Some (snd lib.name))
652657
~obj_dir
653658
~dialects:(Dune_project.dialects (Scope.project scope))
654-
~ident:(Merlin_ident.for_lib (Library.best_name lib))
659+
~ident:merlin_ident
655660
~for_
656661
~parameters
657662
in
@@ -701,7 +706,7 @@ let compile_context (lib : Library.t) ~sctx ~dir_contents ~expander ~scope ~for_
701706
let rules (lib : Library.t) ~sctx ~dir_contents ~expander ~scope =
702707
let dir = Dir_contents.dir dir_contents in
703708
let buildable = lib.buildable in
704-
let f ~for_ ~for_merlin =
709+
let f ~for_ ~for_merlin ~merlin_ident =
705710
let* local_lib, compile_info, source_modules, parameters =
706711
compile_context_data lib ~dir_contents ~scope ~for_
707712
in
@@ -735,6 +740,7 @@ let rules (lib : Library.t) ~sctx ~dir_contents ~expander ~scope =
735740
~compile_info
736741
~ctx_dir:dir
737742
~for_merlin
743+
~merlin_ident
738744
in
739745
cctx, merlin
740746
in
@@ -751,10 +757,14 @@ let rules (lib : Library.t) ~sctx ~dir_contents ~expander ~scope =
751757
~dir
752758
~lib_config
753759
in
754-
let merlin_ident = Merlin_ident.for_lib (Library.best_name lib) in
755760
let { Compilation_mode.for_merlin; modes } =
756761
Compilation_mode.of_mode_set (Lib_info.modes lib_info)
757762
in
763+
let mode_suffix =
764+
match modes with
765+
| _ :: _ :: _ -> true
766+
| [] | [ _ ] -> false
767+
in
758768
Memo.parallel_map modes ~f:(fun for_ ->
759769
let buildable = lib.buildable in
760770
let libs = Scope.libs scope in
@@ -769,14 +779,17 @@ let rules (lib : Library.t) ~sctx ~dir_contents ~expander ~scope =
769779
~allow_overlaps:buildable.allow_overlapping_dependencies
770780
in
771781
let* () = Buildable_rules.gen_select_rules sctx compile_info ~dir ~for_ in
782+
let merlin_ident =
783+
Merlin_ident.for_lib (Library.best_name lib) ~for_ ~mode_suffix
784+
in
772785
let+ r =
773786
Buildable_rules.with_lib_deps
774787
(Super_context.context sctx)
775788
merlin_ident
776789
~dir
777790
~f:(fun () ->
778791
let for_merlin = Compilation_mode.equal for_ for_merlin in
779-
f ~for_ ~for_merlin)
792+
f ~for_ ~for_merlin ~merlin_ident)
780793
in
781794
for_, Some r)
782795
in

src/dune_rules/merlin/merlin_ident.ml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
open Import
22

33
type t =
4-
| Lib of Lib_name.t
4+
| Lib of Lib_name.t * [ `Mode_suffix of Compilation_mode.t | `No_suffix ]
55
| Exes of string Nonempty_list.t
66
| Melange_entries of string
77

8-
let for_lib l = Lib l
8+
let for_lib l ~for_ ~mode_suffix =
9+
Lib (l, if mode_suffix then `Mode_suffix for_ else `No_suffix)
10+
;;
11+
912
let for_exes ~names = Exes names
1013
let for_melange ~target = Melange_entries target
1114

1215
(* For debug purposes we use the name of one library or executable and the hash
1316
of the others if there are multiple executables to name the merlin file *)
1417
let to_string = function
15-
| Lib name -> sprintf "lib-%s" (Lib_name.to_string name)
18+
| Lib (name, (`No_suffix | `Mode_suffix Ocaml)) ->
19+
sprintf "lib-%s" (Lib_name.to_string name)
20+
| Lib (name, `Mode_suffix Melange) -> sprintf "lib-%s-melange" (Lib_name.to_string name)
1621
| Exes [ name ] -> sprintf "exe-%s" name
1722
| Exes (name :: names) ->
1823
sprintf "exe-%s-%s" name Digest.(repr (Repr.list String.repr) names |> to_string)

src/dune_rules/merlin/merlin_ident.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ open Import
44
to a specific [library] or [executable] stanza. *)
55
type t
66

7-
val for_lib : Lib_name.t -> t
7+
val for_lib : Lib_name.t -> for_:Compilation_mode.t -> mode_suffix:bool -> t
88
val for_exes : names:string Nonempty_list.t -> t
99
val for_melange : target:string -> t
1010

test/blackbox-tests/test-cases/melange/merlin.t

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,3 +496,99 @@ User ppx flags should appear in merlin config
496496
]
497497
]
498498
}
499+
500+
Mixed OCaml/Melange libraries generate separate Merlin configuration files.
501+
502+
$ mkdir mixed
503+
$ cat > mixed/dune-project <<EOF
504+
> (lang dune 3.24)
505+
> (using melange 0.1)
506+
> EOF
507+
$ cat > mixed/pp_ocaml.sh <<'EOF'
508+
> #!/bin/sh
509+
> cat "$1"
510+
> EOF
511+
$ cat > mixed/pp_melange.sh <<'EOF'
512+
> #!/bin/sh
513+
> cat "$1"
514+
> EOF
515+
$ chmod +x mixed/pp_ocaml.sh mixed/pp_melange.sh
516+
$ cat > mixed/dune <<EOF
517+
> (library
518+
> (name mixed)
519+
> (modules foo)
520+
> (modes :standard melange)
521+
> (preprocess
522+
> (action
523+
> (run sh %{dep:pp_ocaml.sh} %{input-file})))
524+
> (melange.preprocess
525+
> (action
526+
> (run sh %{dep:pp_melange.sh} %{input-file}))))
527+
> EOF
528+
$ cat > mixed/foo.ml <<EOF
529+
> let x = "foo"
530+
> EOF
531+
532+
$ dune build --root mixed @check
533+
$ find mixed/_build/default/.merlin-conf -type f | sort
534+
mixed/_build/default/.merlin-conf/lib-mixed
535+
mixed/_build/default/.merlin-conf/lib-mixed-melange
536+
537+
The old `File` query still returns the default OCaml Merlin configuration.
538+
539+
$ query_ocaml_merlin_pp "$PWD/mixed/foo.ml" --root mixed | grep -E 'STDLIB|\(B .*\.mixed\.objs'
540+
(STDLIB /OCAMLC_WHERE)
541+
(B $TESTCASE_ROOT/mixed/_build/default/.mixed.objs/byte)
542+
$ query_ocaml_merlin_pp "$PWD/mixed/foo.ml" --root mixed | grep -E 'MELC_STDLIB|\.objs/melange|pp_melange'
543+
[1]
544+
545+
Both generated configurations remain available to debug tooling.
546+
547+
$ dune ocaml merlin dump-config --root mixed --format=json "$PWD/mixed" | jq '
548+
> include "dune";
549+
> def local_path:
550+
> gsub("^.*test/blackbox-tests/test-cases/melange/merlin/mixed"; "$TESTCASE_ROOT/mixed")
551+
> | sub("^.*_build/default/"; "_build/default/");
552+
> def mode:
553+
> if
554+
> [ .config[] | select(.[0] == "B") | .[1] ]
555+
> | any(contains(".objs/melange"))
556+
> then "melange" else "ocaml" end;
557+
> [
558+
> .[]
559+
> | select(.module_name == "Foo")
560+
> | {
561+
> mode: mode,
562+
> obj_dir:
563+
> [ .config[]
564+
> | select(.[0] == "B")
565+
> | .[1]
566+
> | select(contains("_build/default"))
567+
> | local_path
568+
> ][0],
569+
> preprocess:
570+
> [ .config[]
571+
> | select(.[0] == "FLG")
572+
> | .[1]
573+
> | select(.[0] == "-pp")
574+
> | .[1]
575+
> | if contains("pp_melange") then "melange" else "ocaml" end
576+
> ]
577+
> | unique
578+
> | .[0]
579+
> }
580+
> ]
581+
> | unique_by(.mode)
582+
> | sort_by(if .mode == "ocaml" then 0 else 1 end)' | censor
583+
[
584+
{
585+
"mode": "ocaml",
586+
"obj_dir": "_build/default/.mixed.objs/byte",
587+
"preprocess": "ocaml"
588+
},
589+
{
590+
"mode": "melange",
591+
"obj_dir": "_build/default/.mixed.objs/melange",
592+
"preprocess": "melange"
593+
}
594+
]

0 commit comments

Comments
 (0)