diff --git a/CHANGES.md b/CHANGES.md index 21f63e0122a1..e83c6b65b86c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,8 @@ Unreleased - Fix parsing of OCaml errors that contain code excerpts with `...` in them. (#7008, @rgrinberg) +- Dune now suggests other aliases when an alias is not found (#7004, @Alizter) + - Pre-emptively clear screen in watch mode (#6987, fixes #6884, @rgrinberg) - Fix cross compilation configuration when a context with targets is itself a diff --git a/bin/alias.ml b/bin/alias.ml index 99ee8d268751..fc3c94641d73 100644 --- a/bin/alias.ml +++ b/bin/alias.ml @@ -79,14 +79,40 @@ let dep_on_alias_rec_multi_contexts ~dir:src_dir ~name ~contexts = let* dir = Action_builder.of_memo (find_dir_specified_on_command_line ~dir:src_dir) in - let+ is_nonempty_list = + let* is_nonempty_list = Action_builder.all (List.map contexts ~f:(fun ctx -> Action_builder.dep_on_alias_rec name ctx dir)) in + let+ load_dir = + Action_builder.all + @@ List.map contexts ~f:(fun ctx -> + let dir = + Source_tree.Dir.path dir + |> Path.Build.append_source (Context_name.build_dir ctx) + |> Path.build + in + Action_builder.of_memo @@ Load_rules.load_dir ~dir) + in let is_nonempty = List.exists is_nonempty_list ~f:Fun.id in if (not is_nonempty) && not (Dune_engine.Alias.is_standard name) then - User_error.raise + let hints = + let rec aliases t = + match (t : Load_rules.Loaded.t list) with + | Build build :: t -> + Alias.Name.Map.union + ~f:(fun _ a _ -> Some a) + build.aliases (aliases t) + | _ :: t -> aliases t + | _ -> Alias.Name.Map.empty + in + User_message.did_you_mean + (Alias.Name.to_string name) + ~candidates: + (Alias.Name.Map.keys (aliases load_dir) + |> List.map ~f:Alias.Name.to_string) + in + User_error.raise ~hints [ Pp.textf "Alias %S specified on the command line is empty." (Dune_engine.Alias.Name.to_string name) ; Pp.textf "It is not defined in %s or any of its descendants." diff --git a/test/blackbox-tests/test-cases/alias-candidates.t/dune b/test/blackbox-tests/test-cases/alias-candidates.t/dune new file mode 100644 index 000000000000..4c3f5aee72bd --- /dev/null +++ b/test/blackbox-tests/test-cases/alias-candidates.t/dune @@ -0,0 +1,4 @@ +(rule + (alias foo) + (action + (echo "Hello, world from \"foo\"!"))) diff --git a/test/blackbox-tests/test-cases/alias-candidates.t/dune-project b/test/blackbox-tests/test-cases/alias-candidates.t/dune-project new file mode 100644 index 000000000000..3c48133ad585 --- /dev/null +++ b/test/blackbox-tests/test-cases/alias-candidates.t/dune-project @@ -0,0 +1 @@ +(lang dune 3.7) diff --git a/test/blackbox-tests/test-cases/alias-candidates.t/run.t b/test/blackbox-tests/test-cases/alias-candidates.t/run.t new file mode 100644 index 000000000000..9e1a592534d9 --- /dev/null +++ b/test/blackbox-tests/test-cases/alias-candidates.t/run.t @@ -0,0 +1,8 @@ +Dune should suggest similar aliases when it cannot find one. + +We have an alias "foo" but let's try to build something misspeled: + $ dune build @fou + Error: Alias "fou" specified on the command line is empty. + It is not defined in . or any of its descendants. + Hint: did you mean fmt or foo? + [1] diff --git a/test/blackbox-tests/test-cases/generated-source-dir-overlap.t b/test/blackbox-tests/test-cases/generated-source-dir-overlap.t index 3c8092119c7a..8f878f343f44 100644 --- a/test/blackbox-tests/test-cases/generated-source-dir-overlap.t +++ b/test/blackbox-tests/test-cases/generated-source-dir-overlap.t @@ -19,6 +19,7 @@ If a generated directory is "overlaid" by a source dir, then things break. $ dune build @foo Error: Alias "foo" specified on the command line is empty. It is not defined in . or any of its descendants. + Hint: did you mean fmt? [1] The command above claims that @foo isn't defined, but it clearly is if we