defmodule Mix.Tasks.Recode.Help do @shortdoc "Lists recode tasks" @moduledoc """ Lists all availbale recode tasks with a short description or prints the documentation for a given recode task. To print the documentation of a task run `mix recode.help {task-name}`. As a task name the module name (e.g. `Nesting`) or the full module name (e.g. `Recode.Task.Nesting`) is accepted. """ use Mix.Task @task_namespace "Recode.Task." @impl Mix.Task def run([]) do :recode |> Application.spec(:modules) |> Enum.filter(&task?/1) |> Enum.group_by(&category/1, &info/1) |> print() end def run([task]) do module = :recode |> Application.spec(:modules) |> Enum.find(fn module -> task?(module, task) end) if module do IEx.Introspection.h(module) :ok else Mix.raise(""" The recode task #{task} could not be found. \ Run "mix recode.help" for a list of recode tasks.\ """) end end def run(_opts) do Mix.raise(""" recode.help does not support this command. For more information run "mix help recode.help"\ """) end defp category(module), do: Recode.Task.category(module) defp task?(module) do task? = module |> inspect() |> String.starts_with?(@task_namespace) task? and not is_nil(Recode.Task.shortdoc(module)) end defp task?(module, name) do with true <- task?(module) do inspect(module) == name or module |> inspect() |> String.trim_leading(@task_namespace) == name end end defp info(module) do name = module |> inspect() |> String.trim_leading(@task_namespace) {name, Recode.Task.shortdoc(module), Recode.Task.corrector?(module)} end defp print(info) do max = max_name_length(info) print("Design tasks:", info.design, max) print("Readability tasks:", info.readability, max) print("Refactor tasks:", info.refactor, max) print("Warning tasks:", info.warning, max) end defp print(section, tasks, max) do IO.puts(section) Enum.each(tasks, fn {task, doc, corrector?} -> type = if corrector?, do: "Corrector -", else: "Checker -" IO.puts(String.pad_trailing(task, max) <> " # #{type} #{doc}") end) end defp max_name_length(info) when is_map(info) do info |> Map.values() |> List.flatten() |> Enum.reduce(0, fn {name, _shortdoc, _corrector?}, max -> max(byte_size(name), max) end) end end