From 9dd34d61e4ac8514ab91143fba6500ef12240d98 Mon Sep 17 00:00:00 2001 From: Milton Mazzarri Date: Thu, 28 May 2015 21:22:40 -0500 Subject: [PATCH] Handle code blocks with and without language spec This commit includes the following: * Improve `pretty_codeblocks` function to work with Hoedown and Pandoc * Add more tests for `pretty_codeblocks` * Delete duplicate code in `ExDoc.Markdown.to_html` * Avoid to run too many Regex.replace expressions * Add logic for pretty blocks in Hoedown and Pandoc --- lib/ex_doc/formatter/html.ex | 12 +++++++++--- lib/ex_doc/markdown.ex | 11 +++-------- lib/ex_doc/markdown/hoedown.ex | 12 ++++++++++++ lib/ex_doc/markdown/pandoc.ex | 13 +++++++++++++ test/ex_doc/formatter/html_test.exs | 10 ++++++++-- test/ex_doc/markdown/hoedown_test.exs | 6 ++++++ test/ex_doc/markdown/pandoc_test.exs | 6 ++++++ 7 files changed, 57 insertions(+), 13 deletions(-) diff --git a/lib/ex_doc/formatter/html.ex b/lib/ex_doc/formatter/html.ex index 700fd19db..38b70c8f3 100644 --- a/lib/ex_doc/formatter/html.ex +++ b/lib/ex_doc/formatter/html.ex @@ -75,11 +75,17 @@ defmodule ExDoc.Formatter.HTML do end @doc false - # Helper to handle plain code blocks (```...```) without + # Helper to handle plain code blocks (```...```) with and without # language specification and indentation code blocks def pretty_codeblocks(bin) do - Regex.replace(~r/
/,
-                  bin, "
")
+    bin = Regex.replace(~r/
\s*iex>/,
+                        # Add "elixir" class for now, until we have support for
+                        # "iex" in highlight.js
+                        bin, "
iex>")
+    bin = Regex.replace(~r/
/,
+                        bin, "
")
+
+    bin
   end
 
   @doc false
diff --git a/lib/ex_doc/markdown.ex b/lib/ex_doc/markdown.ex
index 609e01d3e..b0463ed27 100644
--- a/lib/ex_doc/markdown.ex
+++ b/lib/ex_doc/markdown.ex
@@ -7,16 +7,11 @@ defmodule ExDoc.Markdown do
 
   @markdown_processor_key :markdown_processor
 
-  def to_html(text) when is_binary(text) do
-    text = get_markdown_processor().to_html(text)
+  import ExDoc.Formatter.HTML, only: [pretty_codeblocks: 1]
 
-    # handle code blocks (```...```) with language specification
-    text = Regex.replace(~r/
\s*iex>/,
-                  #add "elixir" class for now, until we have support for iex in highlight.js
-                  text, "
iex>")
+  def to_html(text) when is_binary(text) do
+    text = get_markdown_processor().to_html(text) |> pretty_codeblocks
 
-    text = Regex.replace(~r/
/,
-                  text, "
")
     text
   end
 
diff --git a/lib/ex_doc/markdown/hoedown.ex b/lib/ex_doc/markdown/hoedown.ex
index e6ff07095..9a720a098 100644
--- a/lib/ex_doc/markdown/hoedown.ex
+++ b/lib/ex_doc/markdown/hoedown.ex
@@ -16,5 +16,17 @@ defmodule ExDoc.Markdown.Hoedown do
       autolink: Keyword.get(opts, :autolink, true),
       fenced_code: Keyword.get(opts, :fenced_code, true),
       tables: Keyword.get(opts, :tables, true))
+    |> pretty_codeblocks
+  end
+
+  @doc false
+  # Helper to handle fenced code blocks (```...```) with
+  # language specification
+  defp pretty_codeblocks(bin) do
+    # Hoedown parser puts the prefix "language-" as part of the class value
+    bin = Regex.replace(~r/
/,
+                        bin, "
")
+
+    bin
   end
 end
diff --git a/lib/ex_doc/markdown/pandoc.ex b/lib/ex_doc/markdown/pandoc.ex
index 72f1f8de7..5c416e671 100644
--- a/lib/ex_doc/markdown/pandoc.ex
+++ b/lib/ex_doc/markdown/pandoc.ex
@@ -15,6 +15,7 @@ defmodule ExDoc.Markdown.Pandoc do
     |> text_to_file()
     |> open_port(opts)
     |> process_port()
+    |> pretty_codeblocks()
   end
 
   defp text_to_file(text) do
@@ -53,4 +54,16 @@ defmodule ExDoc.Markdown.Pandoc do
         {status, List.to_string(data)}
     end
   end
+
+  @doc false
+  # Helper to handle fenced code blocks (```...```) with
+  # language specification
+  defp pretty_codeblocks(bin) do
+    # Pandoc parser puts the class attribute inside the `pre` tag
+    # Move the class attribute to the code element to keep consistency.
+    bin = Regex.replace(~r//,
+                        bin, "
")
+
+    bin
+  end
 end
diff --git a/test/ex_doc/formatter/html_test.exs b/test/ex_doc/formatter/html_test.exs
index 048eb9773..34c36d930 100644
--- a/test/ex_doc/formatter/html_test.exs
+++ b/test/ex_doc/formatter/html_test.exs
@@ -92,10 +92,16 @@ defmodule ExDoc.Formatter.HTMLTest do
   test "make markdown codeblocks pretty" do
     with_empty_class = "
mix run --no-halt path/to/file.exs"
     without_class = "
mix run --no-halt path/to/file.exs"
+    iex_detected_with_empty_class = "
iex> max(4, 5)"
+    iex_detected_without_class = "
iex> max(4, 5)"
 
     assert HTML.pretty_codeblocks(with_empty_class) ==
-           "
mix run --no-halt path/to/file.exs"
+           "
mix run --no-halt path/to/file.exs"
     assert HTML.pretty_codeblocks(without_class) ==
-           "
mix run --no-halt path/to/file.exs"
+           "
mix run --no-halt path/to/file.exs"
+    assert HTML.pretty_codeblocks(iex_detected_with_empty_class) ==
+          "
iex> max(4, 5)"
+    assert HTML.pretty_codeblocks(iex_detected_without_class) ==
+          "
iex> max(4, 5)"
   end
 end
diff --git a/test/ex_doc/markdown/hoedown_test.exs b/test/ex_doc/markdown/hoedown_test.exs
index 28a83956a..a5ccbace4 100644
--- a/test/ex_doc/markdown/hoedown_test.exs
+++ b/test/ex_doc/markdown/hoedown_test.exs
@@ -23,4 +23,10 @@ defmodule ExDoc.Markdown.HoedownTest do
   test "to_html handles empty input" do
     assert Markdown.to_html("") == ""
   end
+
+  test "pretty Markdown fenced code blocks for Hoedown" do
+    hoedown_with_language_specified = "```elixir\nmix run --no-halt path/to/file.exs\n```"
+    expected = "
mix run --no-halt path/to/file.exs\n
\n" + assert Markdown.to_html(hoedown_with_language_specified) == expected + end end diff --git a/test/ex_doc/markdown/pandoc_test.exs b/test/ex_doc/markdown/pandoc_test.exs index 3c671cbe2..91b177f52 100644 --- a/test/ex_doc/markdown/pandoc_test.exs +++ b/test/ex_doc/markdown/pandoc_test.exs @@ -30,4 +30,10 @@ defmodule MarkdownTest.PandocTest do test "to_html converts to rst" do assert Markdown.to_html("`hello`", format: "rst") == "``hello``\n" end + + test "pretty Markdown fenced code blocks for Pandoc" do + pandoc_with_language_specified = "```elixir\nmix run --no-halt path/to/file.exs\n```" + expected = "
mix run --no-halt path/to/file.exs
\n" + assert Markdown.to_html(pandoc_with_language_specified) == expected + end end