README.md

# Pandoc

A watcher and a Mix task that uses Pandoc to convert markdown files to html.

## Requirements

- inotify-tools
- pandoc

## Installation

```elixir
# mix.exs

def deps do
  [
    {:pandoc, "~> 0.2.0", runtime: Mix.env() == :dev}
  ]
end
```

## Use

```elixir
# mix.exs

# ...
defp aliases do
  [
    # ...
    "documents.build": ["pandoc hello"],
    "statics.build": ["assets.build", "documents.build"],
    "statics.deploy": ["assets.deploy", "documents.build"]
  ]
end
```

```elixir
# config/config.exs

config :pandoc,
  hello: [
    args: ~w(--mathjax -o ../priv/static/posts),
    cd: Path.expand("../documents", __DIR__)
  ]
```

```elixir
# config/dev.exs

config :hello, HelloWeb.Endpoint,
  # ...
  watchers: [
    # ...
    pandoc: {Pandoc, :run, [:hello, ~w(--watch)]}
  ]

config :pandoc, hello: [pattern: "**/*.md"]
```

```elixir
# lib/hello_web/router.ex

  scope "/", HelloWeb do
    pipe_through :browser

    get "/drafts/:id", PostController, :draft
    get "/posts/:id", PostController, :show
    get "/posts", PostController, :index

    get "/", PageController, :home
  end
```

```elixir
# lib/hello_web/controllers/posts_controller.ex

defmodule HelloWeb.PostController do
  use HelloWeb, :controller

  alias Hello.Document
  @path "documents/**/*.md"
  paths = Path.wildcard(@path)
  @paths_hash :erlang.md5(paths)
  for path <- paths, do: @external_resource(path)
  @posts Document.list()

  def __mix_recompile__?(), do: @path |> Path.wildcard() |> :erlang.md5() != @paths_hash

  def index(conn, _params) do
    render(conn, :index, posts: @posts)
  end

  def show(conn, %{"id" => id}) do
    assigns = [
      post: :hello |> :code.priv_dir() |> Path.join("static/posts/#{id}.html") |> File.read!()
    ]

    render(conn, :show, assigns)
  end

  def drafts(conn, %{"id" => id}) do
    config = Application.get_env(:pandoc, :hello)

    opts = [
      cd: config[:cd] || File.cwd!()
    ]

    filename = List.keyfind(@posts, id, 0) |> elem(1) |> Map.get(:filename)
    path = Path.join("_drafts", filename)

    render(conn, :show, post: "pandoc" |> System.cmd([path], opts) |> elem(0))
  end
```

```elixir
# lib/hello/document.ex

defmodule Stasis.Document do
  require Logger

  @ext ".md"
  @pattern Application.compile_env(:pandoc, [:hello, :pattern])

  def list() do
    "documents"
    |> Path.join(@pattern)
    |> Path.wildcard()
    |> Enum.map(fn path -> {Path.basename(path), path} end)
    |> Enum.sort(fn {basename_a, _}, {basename_b, _} -> basename_a < basename_b end)
    |> Enum.reduce([], fn {filename, path}, acc ->
      id = Path.rootname(filename, @ext)
      data = if "_drafts" in Path.split(path), do: %{:draft, true}, else: %{}

      [{id, data} | acc]
    end)
  end
```

```elixir
# lib/hello_web/controllers/post_html.ex

# ...

defp href(filename, draft \\ false) do
  root = (draft && "/drafts") || "/posts"
  Path.join(root, filename |> Path.basename(".md"))
end

```

```heex
<!-- lib/hello_web/controllers/post_html/index.html.heex -->

<%= for {id, data} <- @posts do %>
  <p>
    <.link href={href(Path.rootname(filename), data[:draft])} method="get">
      <%= id %>
    </.link>
  </p>
<% end %>
```

```heex
<!-- lib/hello_web/controllers/post_html/show.html.heex -->

<%= raw(@post) %>
```