Web Dev Solutions

Catalin Mititiuc

From b8d8b3dbd88ab42fc8f050af0d18fc4dd66d7ffe Mon Sep 17 00:00:00 2001 From: Catalin Mititiuc Date: Thu, 9 Jan 2025 11:25:52 -0800 Subject: Handle installing Pandoc --- README.md | 187 +++++++++++++++++++++++--------------------------------------- 1 file changed, 68 insertions(+), 119 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index 9a00282..3255f4b 100644 --- a/README.md +++ b/README.md @@ -1,168 +1,117 @@ # Pandoc -A watcher and a Mix task that uses Pandoc to convert markdown files to html. +A watcher and Mix tasks for installing and invoking [pandoc](https://pandoc.org/). ## Requirements -- inotify-tools -- pandoc +Currently only supports `linux-amd64` architectures. ## Installation -```elixir -# mix.exs +If you are going to convert markup in production, then you add `pandoc` as +dependency on all environments but only start it in dev: +```elixir def deps do [ - {:pandoc, "~> 0.2.0", runtime: Mix.env() == :dev} + {:pandoc, "~> 0.3", runtime: Mix.env() == :dev} ] end ``` -## Use +However, if your markup is preconverted during development, then it only needs +to be a dev dependency: ```elixir -# mix.exs - -# ... -defp aliases do +def deps do [ - # ... - "documents.build": ["pandoc hello"], - "statics.build": ["assets.build", "documents.build"], - "statics.deploy": ["assets.deploy", "documents.build"] + {:pandoc, "~> 0.3", only: :dev} ] end ``` -```elixir -# config/config.exs - -config :pandoc, - hello: [ - args: ~w(--mathjax -o ../priv/static/posts), - cd: Path.expand("../documents", __DIR__) - ] -``` +Once installed, change your `config/config.exs` to pick your pandoc version of +choice: ```elixir -# config/dev.exs - -config :hello, HelloWeb.Endpoint, - # ... - watchers: [ - # ... - pandoc: {Pandoc, :run, [:hello, ~w(--watch)]} - ] - -config :pandoc, hello: [pattern: "**/*.md"] +config :pandoc, version: "3.6.1" ``` -```elixir -# lib/hello_web/router.ex - - scope "/", HelloWeb do - pipe_through :browser +Now you can install pandoc by running: - get "/drafts/:id", PostController, :draft - get "/posts/:id", PostController, :show - get "/posts", PostController, :index - - get "/", PageController, :home - end +```bash +$ mix pandoc.install ``` -```elixir -# lib/hello_web/controllers/posts_controller.ex - -defmodule HelloWeb.PostController do - use HelloWeb, :controller +And invoke pandoc with: - 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() +```bash +$ mix pandoc default documents/hello.md -o priv/static/posts/hello.html +``` - def __mix_recompile__?(), do: @path |> Path.wildcard() |> :erlang.md5() != @paths_hash +The executable is kept at `_build/pandoc-TARGET`. Where `TARGET` is your +system target architecture. - def index(conn, _params) do - render(conn, :index, posts: @posts) - end +## Profiles - def show(conn, %{"id" => id}) do - assigns = [ - post: :hello |> :code.priv_dir() |> Path.join("static/posts/#{id}.html") |> File.read!() - ] +The first argument to `pandoc` is the execution profile. You can define multiple +execution profiles with the current directory, the OS environment, and default +arguments to the `pandoc` task: - render(conn, :show, assigns) - end +```elixir +config :pandoc, + version: "3.6.1", + default: [ + args: ~w(--mathjax), + cd: Path.expand("../documents", __DIR__) + ] +``` - def drafts(conn, %{"id" => id}) do - config = Application.get_env(:pandoc, :hello) +When `mix pandoc default` is invoked, the task arguments will be appended to +the ones configured above. Note profiles must be configured in your +`config/config.exs`, as `pandoc` runs without starting your application (and +therefore it won't pick settings in `config/runtime.exs`). - opts = [ - cd: config[:cd] || File.cwd!() - ] +## Adding to Phoenix - filename = List.keyfind(@posts, id, 0) |> elem(1) |> Map.get(:filename) - path = Path.join("_drafts", filename) +To add `pandoc` to an application using Phoenix, you will need Phoenix v1.6+ and +the following steps. - render(conn, :show, post: "pandoc" |> System.cmd([path], opts) |> elem(0)) - end -``` +First add it as a dependency in your `mix.exs`: ```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 +def deps do + [ + {:phoenix, "~> 1.6"}, + {:pandoc, "~> 0.3", runtime: Mix.env() == :dev} + ] +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 +Now let's change `config/config.exs` to configure `pandoc` to write to +`priv/static/posts`: +```elixir +config :pandoc, + version: "3.6.1", + default: [ + args: fn extra_args -> + {_, [input_file], _} = OptionParser.parse(extra_args, switches: []) + ~w(--output=../priv/static/posts/#{Path.rootname(input_file)}.html) + end, + cd: Path.expand("../documents", __DIR__) + ] ``` -```heex - +For development, we want to enable the watcher. So find the `watchers` +configuration in your `config/dev.exs` and add: -<%= for {id, data} <- @posts do %> -

- <.link href={href(Path.rootname(filename), data[:draft])} method="get"> - <%= id %> - -

-<% end %> +```elixir +pandoc: {Pandoc, :watch, [:default]} ``` -```heex - +Note we are enabling the file system watcher. -<%= raw(@post) %> -``` +## Licence + +pandoc source code is licensed under the MIT License. -- cgit v1.2.3