defmodule JacobCli.Commands.Help do use Jacob.Command name("help") desc("Show some help") doc(""" # Help command Return help informations about the current cli. """) @doc false def run([command_name]) do case Jacob.Command.Server.find(command_name) do {:ok, command_module} -> print_doc(command_module) :error -> command_does_not_exists(command_name) end end @doc false def run(_) do write(""" #{Jacob.console_name() |> String.capitalize()} - Jacob #{Jacob.version()} Available commands: #{Jacob.Command.Server.all() |> remove_hidden_commands() |> command_list} Need more help ? Well, I guess you'll have to read the source ¯\\_(ツ)_/¯. """) end defp print_doc(command_module) do IO.ANSI.Docs.print_heading(command_module.name) command_module.doc |> IO.ANSI.Docs.print() end defp command_does_not_exists(command_name) do error("Command #{command_name} does not exists.") end defp command_list(commands) do commands |> prepare_commands_for_print() |> build_list() end defp prepare_commands_for_print([]), do: [] defp prepare_commands_for_print([{_, command} | rest]) do [{command.name, command.desc} | prepare_commands_for_print(rest)] end defp build_list(commands) do build_list(commands, find_max(commands), "") end defp build_list([], _, acc), do: acc defp build_list([{name, desc} | rest], max, acc) do name = name |> String.pad_trailing(max) command = " #{name} #{desc}\n" build_list(rest, max, acc <> command) end defp find_max(commands) do Enum.reduce(commands, 0, fn {name, _}, max -> current = String.length(name) if current > max, do: current, else: max end) end defp remove_hidden_commands(commands) do Enum.filter(commands, fn {_, command} -> !command.hidden? end) end end