1defmodule Earmark.CLI do
2
3  def main(argv) do
4    argv
5    |> parse_args
6    |> process
7  end
8
9  @args """
10  usage:
11
12     earmark --help
13     earmark --version
14     earmark [ options... <file> ]
15
16  convert file from Markdown to HTML.
17
18     where options can be any of:
19       -- code_class_prefix -- gfm -- smartypants -- pedantic -- breaks
20
21  """
22
23  @cli_options [:code_class_prefix, :gfm, :smartypants, :pedantic, :breaks]
24
25  defp parse_args(argv) do
26    switches = [
27      help: :boolean,
28      version: :boolean
29      ]
30    aliases = [
31      h: :help,
32      v: :version
33    ]
34
35    parse = OptionParser.parse(argv, switches: switches, aliases: aliases)
36    case  parse  do
37      { [ {switch, true } ],  _, _ } -> switch
38      { options, [ filename ],  _ }  -> {open_file(filename), options}
39      { options, [ ],           _ }  -> {:stdio, options}
40      _                              -> :help
41    end
42  end
43
44
45  defp process(:help) do
46    IO.puts(:stderr, @args)
47    IO.puts(:stderr, option_related_help())
48  end
49
50  defp process(:version) do
51    IO.puts( Earmark.version() )
52  end
53
54  defp process({io_device, options}) do
55    options = struct(Earmark.Options, booleanify(options))
56    content = IO.stream(io_device, :line) |> Enum.to_list
57    Earmark.as_html!(content, options)
58    |> IO.puts
59  end
60
61
62
63  defp booleanify( keywords ), do: Enum.map(keywords, &booleanify_option/1)
64  defp booleanify_option({k, v}) do
65    {k,
66     case Map.get %Earmark.Options{}, k, :does_not_exist do
67        true  -> if v == "false", do: false, else: true
68        false -> if v == "false", do: false, else: true
69        :does_not_exist ->
70          IO.puts( :stderr, "ignoring unsupported option #{inspect k}")
71          v
72        _     -> v
73      end
74    }
75  end
76
77  defp open_file(filename), do: io_device(File.open(filename, [:utf8]), filename)
78
79  defp io_device({:ok, io_device}, _), do: io_device
80  defp io_device({:error, reason}, filename) do
81    IO.puts(:stderr, "#{filename}: #{:file.format_error(reason)}")
82    exit(1)
83  end
84
85  defp option_related_help do
86    @cli_options
87    |> Enum.map(&specific_option_help/1)
88    |> Enum.join("\n")
89  end
90
91  defp specific_option_help( option ) do
92    "      --#{option} defaults to #{inspect(Map.get(%Earmark.Options{}, option))}"
93  end
94
95end
96
97# SPDX-License-Identifier: Apache-2.0
98