defmodule EditorConfig.CLI do @moduledoc "Escript entrypoint for the `editorconfig` command." @switches [f: :string, b: :string, version: :boolean, files: :boolean, help: :boolean] @aliases [f: :f, b: :b, v: :version, h: :help] @spec main([String.t()]) :: no_return() def main(argv) do {status, output} = run(argv) IO.write(output) System.halt(status) end @spec run([String.t()]) :: {non_neg_integer(), String.t()} def run(argv) do case OptionParser.parse(argv, strict: @switches, aliases: @aliases) do {opts, paths, []} -> dispatch(opts, paths) {_opts, _paths, invalid} -> {2, "invalid option: #{inspect(invalid)}\n"} end end defp dispatch(opts, paths) do cond do opts[:help] -> {0, help()} opts[:version] -> {0, version()} paths == [] -> {2, "missing FILEPATH\n\n" <> help()} true -> resolve_paths(paths, opts) end end defp resolve_paths(paths, opts) do config_name = Keyword.get(opts, :f, ".editorconfig") version = Keyword.get(opts, :b, EditorConfig.spec_version()) show_files? = Keyword.get(opts, :files, false) results = Enum.map(paths, fn path -> if show_files? do EditorConfig.properties_with_sources(path, config_name: config_name, version: version ) else EditorConfig.properties(path, config_name: config_name, version: version) end end) format_results(paths, results, show_files?) end defp format_results(paths, results, show_files?) do output = paths |> Enum.zip(results) |> Enum.map_join("", &format_result(&1, length(paths) > 1, show_files?)) status = if Enum.any?(results, &match?({:error, _reason}, &1)), do: 1, else: 0 {status, output} end defp format_result({path, {:ok, props}}, multi?, false) do header = if multi?, do: "[#{path}]\n", else: "" header <> format_props(props) end defp format_result({path, {:ok, props, sources}}, multi?, true) do header = if multi?, do: "[#{path}]\n", else: "" source_lines = Enum.map_join(sources, "\n", fn {file, section} -> "#{file}: [#{section}]" end) header <> source_lines <> "\n" <> format_props(props) end defp format_result({_path, {:error, reason}}, _multi?, _show_files?), do: "error: #{inspect(reason)}\n" defp format_props(props) do props |> Enum.sort_by(fn {key, _value} -> key end) |> Enum.map_join("", fn {key, value} -> "#{key}=#{value}\n" end) end defp version do "EditorConfig Elixir Core v#{EditorConfig.version()} - Specification Version #{EditorConfig.spec_version()}\n" end defp help do """ editorconfig [options] -f config filename other than .editorconfig -b target specification version -v, --version print version --files print the files and sections that contributed -h, --help print help """ end end