Skip to content

Commit

Permalink
Pretty print alias definition in mix help (#13066)
Browse files Browse the repository at this point in the history
  • Loading branch information
pnezis authored Nov 10, 2023
1 parent 9eb86db commit 98f412c
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 24 deletions.
50 changes: 47 additions & 3 deletions lib/mix/lib/mix/tasks/help.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ defmodule Mix.Tasks.Help do
$ mix help --search PATTERN - prints all tasks and aliases that contain PATTERN in the name
$ mix help --names - prints all task names and aliases
(useful for autocompleting)
$ mix help --aliases - prints all aliases
## Colors
Expand Down Expand Up @@ -69,6 +70,16 @@ defmodule Mix.Tasks.Help do
end
end

def run(["--aliases"]) do
loadpaths!()

aliases = load_aliases()

{docs, max} = build_doc_list([], aliases)

display_doc_list(docs, max)
end

def run(["--search", pattern]) do
loadpaths!()

Expand Down Expand Up @@ -194,13 +205,35 @@ defmodule Mix.Tasks.Help do
end

defp build_alias_doc_list(aliases) do
Enum.reduce(aliases, {[], 0}, fn {alias_name, _task_name}, {docs, max} ->
doc = "Alias defined in mix.exs"
Enum.reduce(aliases, {[], 0}, fn {alias_name, task}, {docs, max} ->
doc = alias_doc(task)
task = "mix " <> alias_name
{[{task, doc} | docs], max(byte_size(task), max)}
end)
end

defp alias_doc(task) do
"Alias for " <> format_alias_doc(task)
end

defp format_alias_doc(task), do: Enum.map_join(List.wrap(task), ", ", &format_alias_task/1)

defp format_alias_task(task) when is_binary(task), do: task

defp format_alias_task(task) when is_function(task) do
info = Function.info(task)
name = Atom.to_string(info[:name])

cond do
info[:type] == :remote -> inspect(task)
info[:type] == :local and String.contains?(name, "/") -> "a function"
true -> "&#{name}/#{info[:arity]}"
end
end

# for invalid aliases
defp format_alias_task(task), do: inspect(task)

defp verbose_doc(task) do
aliases = load_aliases()

Expand All @@ -221,7 +254,18 @@ defmodule Mix.Tasks.Help do
end

defp alias_doc(task_name, note) do
{"Alias for " <> inspect(task_name), "mix.exs", note}
alias_doc = """
Alias for
#{format_alias(task_name)}
"""

{alias_doc, "mix.exs", note}
end

defp format_alias(task) do
inspect(task, pretty: true, width: 0)
|> String.replace("\n", "\n ")
end

defp task_doc(task) do
Expand Down
88 changes: 67 additions & 21 deletions lib/mix/test/mix/tasks/help_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,6 @@ defmodule Mix.Tasks.HelpTest do
end
end

test "help lists all aliases", context do
in_tmp(context.test, fn ->
Mix.Project.push(Aliases)

Mix.Tasks.Help.run([])

assert_received {:mix_shell, :info, ["mix h" <> message]}
assert message =~ ~r/# Alias defined in mix.exs/

assert_received {:mix_shell, :info, ["mix c" <> message]}
assert message =~ ~r/# Alias defined in mix.exs/
end)
end

test "help --names", context do
in_tmp(context.test, fn ->
Mix.Project.push(Aliases)
Expand All @@ -63,11 +49,50 @@ defmodule Mix.Tasks.HelpTest do
aliases: [
h: "hello",
p: &inspect/1,
foo: &foo/1,
bar: fn _ -> :ok end,
help: ["help", "hello"],
"nested.h": [&Mix.shell().info(inspect(&1)), "h foo bar"]
"nested.h": [&Mix.shell().info(inspect(&1)), "h foo bar"],
other: [
"format --check-formatted",
fn _ -> :ok end,
&foo/1,
"help"
]
]
]
end

defp foo(_), do: :ok
end

test "help lists all aliases", context do
in_tmp(context.test, fn ->
Mix.Project.push(ComplexAliases)

Mix.Tasks.Help.run([])

assert_received {:mix_shell, :info, ["mix h" <> message]}
assert message =~ ~r/# Alias for hello/

assert_received {:mix_shell, :info, ["mix p" <> message]}
assert message =~ ~r/# Alias for &inspect\/1/

assert_received {:mix_shell, :info, ["mix foo" <> message]}
assert message =~ ~r/# Alias for &foo\/1/

assert_received {:mix_shell, :info, ["mix bar" <> message]}
assert message =~ ~r/# Alias for a function/

assert_received {:mix_shell, :info, ["mix help" <> message]}
assert message =~ ~r/# Alias for help, hello/

assert_received {:mix_shell, :info, ["mix nested.h" <> message]}
assert message =~ ~r/# Alias for a function, h foo bar/

assert_received {:mix_shell, :info, ["mix other" <> message]}
assert message =~ ~r/# Alias for format --check-formatted, a function, &foo\/1, help/
end)
end

test "help ALIAS", context do
Expand All @@ -80,7 +105,8 @@ defmodule Mix.Tasks.HelpTest do
end)

assert output =~ "mix h\n\n"
assert output =~ "Alias for \"hello\"\n"
assert output =~ "Alias for\n\n"
assert output =~ " \"hello\"\n"
assert output =~ ~r/^Location: mix.exs/m

output =
Expand All @@ -89,7 +115,8 @@ defmodule Mix.Tasks.HelpTest do
end)

assert output =~ "mix p\n\n"
assert output =~ "Alias for &Kernel.inspect/1\n"
assert output =~ "Alias for\n\n"
assert output =~ " &Kernel.inspect/1\n"
assert output =~ ~r/^Location: mix.exs/m

output =
Expand All @@ -98,7 +125,9 @@ defmodule Mix.Tasks.HelpTest do
end)

assert output =~ "mix help\n\n"
assert output =~ "Alias for [\"help\", \"hello\"]\n"
assert output =~ "Alias for\n\n"
assert output =~ " [\"help\",\n"
assert output =~ " \"hello\"]\n"
assert output =~ ~r/^Location: mix.exs/m

output =
Expand All @@ -107,7 +136,8 @@ defmodule Mix.Tasks.HelpTest do
end)

assert output =~ "mix nested.h\n\n"
assert output =~ ~r/Alias for \[#Function/
assert output =~ "Alias for\n\n"
assert output =~ ~r/ \[#Function/
assert output =~ ~r/^Location: mix.exs/m
end)
end
Expand Down Expand Up @@ -149,7 +179,8 @@ defmodule Mix.Tasks.HelpTest do
end)

assert output =~ "mix compile\n\n"
assert output =~ "Alias for \"compile\"\n"
assert output =~ "Alias for\n\n"
assert output =~ "\"compile\"\n"
assert output =~ ~r/^Location: mix.exs/m

assert output =~
Expand All @@ -172,7 +203,7 @@ defmodule Mix.Tasks.HelpTest do

Mix.Tasks.Help.run(["--search", "h"])
assert_received {:mix_shell, :info, ["mix h" <> message]}
assert message =~ ~r/# Alias defined in mix.exs/
assert message =~ ~r/# Alias for hello/
end)
end

Expand All @@ -193,6 +224,21 @@ defmodule Mix.Tasks.HelpTest do
end)
end

test "help --aliases", context do
in_tmp(context.test, fn ->
Mix.Project.push(Aliases)

Mix.Tasks.Help.run(["--aliases"])
assert_received {:mix_shell, :info, ["mix h" <> message]}
assert message =~ ~r/# Alias for hello/

assert_received {:mix_shell, :info, ["mix c" <> message]}
assert message =~ ~r/# Alias for compile/

refute_received {:mix_shell, :info, ["mix deps" <> _]}
end)
end

test "bad arguments" do
message = "Unexpected arguments, expected \"mix help\" or \"mix help TASK\""

Expand Down

0 comments on commit 98f412c

Please sign in to comment.