From 8895db642bfb40d9487e6e708cf38e2b83c2bc43 Mon Sep 17 00:00:00 2001 From: RobertDober Date: Mon, 29 Jul 2019 15:41:09 +0200 Subject: [PATCH] Fixes: #236 --- lib/earmark/html_renderer.ex | 11 +-- lib/earmark/plugin.ex | 113 +------------------------- test/regressions/i106_plugin_test.exs | 17 ++-- 3 files changed, 20 insertions(+), 121 deletions(-) diff --git a/lib/earmark/html_renderer.ex b/lib/earmark/html_renderer.ex index 6b584e9b..d5615da5 100644 --- a/lib/earmark/html_renderer.ex +++ b/lib/earmark/html_renderer.ex @@ -5,7 +5,7 @@ defmodule Earmark.HtmlRenderer do import Earmark.Inline, only: [convert: 3] import Earmark.Helpers, only: [escape: 2] import Earmark.Helpers.HtmlHelpers - import Earmark.Message, only: [add_messages_from: 2, add_messages: 2, get_messages: 1] + import Earmark.Message, only: [add_messages_from: 2, add_message: 2, add_messages: 2, get_messages: 1] import Earmark.Context, only: [append: 2, set_value: 2] import Earmark.Options, only: [get_mapper: 1] @@ -190,11 +190,12 @@ defmodule Earmark.HtmlRenderer do # Plugins # ########### - defp render_block(%Block.Plugin{lines: lines, handler: handler}, context) do + defp render_block(%Block.Plugin{lines: [{_, lnb}|_]=lines, handler: handler}, context) do + context1 = add_message(context, {:deprecation, "DEPRECATED: Plugins will be removed in Earmark 1.4", lnb}) case handler.as_html(lines) do - html when is_list(html) -> {context, html} - {html, errors} -> {add_messages(context, errors), html} - html -> {context, [html]} + html when is_list(html) -> {context1, html} + {html, errors} -> {add_messages(context1, errors), html} + html -> {context1, [html]} end end diff --git a/lib/earmark/plugin.ex b/lib/earmark/plugin.ex index cf573646..b96d9fd9 100644 --- a/lib/earmark/plugin.ex +++ b/lib/earmark/plugin.ex @@ -3,126 +3,17 @@ defmodule Earmark.Plugin do alias Earmark.Options @moduledoc """ - Plugins are modules that implement a render function. Right now that is `as_html`. - - ### Plugin API - - #### Plugin Registration - - When invoking `Earmark.as_html(some_md, options)` we can register plugins inside the `plugins` map, where - each plugin is a value pointed to by the prefix triggering it. - - Prefixes are appended to `"$$"` and lines starting by that string will be rendered by the registered plugin. - - `%Earmark.Options{plugins: %{"" => CommentPlugin}}` would trigger the `CommentPlugin` for each block of - lines prefixed by `$$`, while `%Earmark.Options{plugins: %{"cp" => CommentPlugin}}` would do the same for - blocks of lines prefixed by `$$cp`. - - Please see the documentation of `Plugin.define` for a convenience function that helps creating the necessary - `Earmark.Options` structs for the usage of plugins. - - #### Plugin Invocation - - `as_html` (or other render functions in the future) is invoked with a list of pairs containing the text - and line number of the lines in the block. As an example, if our plugin was registered with the default prefix - of `""` and the markdown to be converted was: - - # Plugin output ahead - $$ line one - $$ - $$ line two - - `as_html` would be invoked as follows: - - as_html([{"line one", 2}, {"", 3}, {"line two", 4}) - - #### Plugin Output - - Earmark's render function will invoke the plugin's render function as explained above. It can then integrate the - return value of the function into the generated rendering output if it complies to the following criteria. - - 1. It returns a string - 1. It returns a list of strings - 1. It returns a pair of lists containing a list of strings and a list of error/warning tuples. - Where the tuples are of the form `{:error | :warning, line_number, descriptive_text}` - - #### A complete example - - iex> defmodule MyPlug do - ...> def as_html(lines) do - ...> # to demonstrate the three possible return values - ...> case render(lines) do - ...> {[line], []} -> line - ...> {lines, []} -> lines - ...> tuple -> tuple - ...> end - ...> end - ...> - ...> defp render(lines) do - ...> Enum.map(lines, &render_line/1) |> Enum.split_with(&ok?/1) - ...> end - ...> - ...> defp render_line({"", _}), do: "
" - ...> defp render_line({"line one", _}), do: "

first line

\\n" - ...> defp render_line({line, lnb}), do: {:error, lnb, line} - ...> - ...> defp ok?({_, _, _}), do: false - ...> defp ok?(_), do: true - ...> end - ...> - ...> lines = [ - ...> "# Plugin Ahead", - ...> "$$ line one", - ...> "$$", - ...> "$$ line two", - ...> ] - ...> Earmark.as_html(lines, Earmark.Plugin.define(MyPlug)) - {:error, "

Plugin Ahead

\\n

first line

\\n
", [{ :error, 4, "line two"}]} - - #### Plugins, reusing Earmark - - As long as you avoid endless recursion there is absolutely no problem to call `Earmark.as_html` in your plugin, consider the following - example in which the plugin will parse markdown and render html verbatim (which is stupid, that is what Earmark already does for you, - but just to demonstrate the possibilities): - - iex> defmodule Again do - ...> def as_html(lines) do - ...> text_lines = Enum.map(lines, fn {str, _} -> str end) - ...> {_, html, errors} = Earmark.as_html(text_lines) - ...> { Enum.join([html | text_lines]), errors } - ...> end - ...> end - ...> lines = [ - ...> "$$a * one", - ...> "$$a * two", - ...> ] - ...> Earmark.as_html(lines, Earmark.Plugin.define({Again, "a"})) - {:ok, "\\n* one* two", []} + DEPRECATED!!! """ @doc """ - adds the definition of one or more plugins to `Earmark.Options`. - - If the plugin is defined with the default prefix and no other options are needed - one can use the one parameter form: - - iex> Earmark.Plugin.define(Earmark) # not a legal plugin of course - %Earmark.Options{plugins: %{"" => Earmark}} - - More then one plugin can be defined, as long as all prefixes differ - - iex> defmodule P1, do: nil - ...> defmodule P2, do: nil - ...> Earmark.Plugin.define([ Earmark, {P1, "p1"}, {P2, "p2"} ]) - %Earmark.Options{plugins: %{"" => Earmark, "p1" => Unit.PluginTest.P1, "p2" => Unit.PluginTest.P2}} + DEPRECATED!!! """ def define(plugin_defs) def define(plugin_defs), do: define(%Options{}, plugin_defs) - def define(options, plugin_defs) - def define(options, plugins) when is_list(plugins) do Enum.reduce(plugins, options, fn plugin, acc -> define(acc, plugin) end) end diff --git a/test/regressions/i106_plugin_test.exs b/test/regressions/i106_plugin_test.exs index cf4c7a98..6a27f851 100644 --- a/test/regressions/i106_plugin_test.exs +++ b/test/regressions/i106_plugin_test.exs @@ -13,7 +13,7 @@ defmodule Regressions.I106PluginTest do """ test "the comment plugin" do assert as_html(@comment_md, %Options{plugins: %{"" => CommentPlugin}}) == - {:ok, "\n", [] } end + {:ok, "\n", [{:deprecation, "DEPRECATED: Plugins will be removed in Earmark 1.4", 1}] } end @comments_md """ $$c comment one $$c comment two @@ -22,7 +22,10 @@ defmodule Regressions.I106PluginTest do """ test "more lines" do assert as_html(@comments_md, Plugin.define({CommentPlugin, "c"})) == - {:error, "\n\n", [{ :warning, 3, "lines for undefined plugin prefix \"unregistered\" ignored (3..3)"}]} + {:error, "\n\n", + [{ :warning, 3, "lines for undefined plugin prefix \"unregistered\" ignored (3..3)"}, + {:deprecation, "DEPRECATED: Plugins will be removed in Earmark 1.4", 1}, + {:deprecation, "DEPRECATED: Plugins will be removed in Earmark 1.4", 4}]} end @more_md """ @@ -33,7 +36,9 @@ defmodule Regressions.I106PluginTest do """ test "even more lines" do assert as_html(@more_md, Plugin.define(%Options{}, [CommentPlugin])) == - {:error, "

line one

\n\n

line two

\n", [{ :warning, 3, "lines for undefined plugin prefix \"c\" ignored (3..3)"}]} + {:error, "

line one

\n\n

line two

\n", + [{ :warning, 3, "lines for undefined plugin prefix \"c\" ignored (3..3)"}, + {:deprecation, "DEPRECATED: Plugins will be removed in Earmark 1.4", 2}]} end @mix_errors """ @@ -45,7 +50,8 @@ defmodule Regressions.I106PluginTest do assert as_html(@mix_errors, Plugin.define(%Options{}, CommentPlugin)) == {:error, "\n

\n",[ { :warning, 1, "lines for undefined plugin prefix \"unregistered\" ignored (1..1)"}, - { :warning, 3, "Unexpected line ="}]} + { :warning, 3, "Unexpected line ="}, + {:deprecation, "DEPRECATED: Plugins will be removed in Earmark 1.4", 2}]} end @error_plugin """ @@ -60,7 +66,8 @@ defmodule Regressions.I106PluginTest do assert as_html(@error_plugin, options) == {:error, "\n

data

\ncorrect", [ {:error, 4, "that is incorrect" }, - {:warning, 5, "lines for undefined plugin prefix \"undef\" ignored (5..5)"}]} + {:warning, 5, "lines for undefined plugin prefix \"undef\" ignored (5..5)"}, + {:deprecation, "DEPRECATED: Plugins will be removed in Earmark 1.4", 1}, {:deprecation, "DEPRECATED: Plugins will be removed in Earmark 1.4", 3}]} end end