File: html_formatter.ex

package info (click to toggle)
elixir-makeup 1.2.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 384 kB
  • sloc: javascript: 24; makefile: 9
file content (146 lines) | stat: -rw-r--r-- 3,704 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
defmodule Makeup.Formatters.HTML.HTMLFormatter do
  @moduledoc """
  Turns a list of tokens into HTML fragments.
  """

  @group_highlight_js "lib/makeup/formatters/html/scripts/group_highlighter_javascript.js" |> File.read!

  defp render_token(escaped_value, css_class, meta, highlight_tag) do
    group_id = meta[:group_id]
    selectable = Map.get(meta, :selectable, [])

    classes = [
      css_class || [],
      if selectable == false do " unselectable" else [] end
    ]

    [
      "<",
      highlight_tag,
      ~S( class="),
      classes,
      ~S("),
      if group_id do [~S( data-group-id="), group_id, ~S(")] else [] end,
      ">",
      escaped_value,
      "</",
      highlight_tag,
      ">",
    ]
  end

  @doc """
  Format a single token into an iolist.
  """
  def format_token({tag, meta, value}, highlight_tag) do
    escaped_value = escape(value)
    css_class = Makeup.Token.Utils.css_class_for_token_type(tag)
    render_token(escaped_value, css_class, meta, highlight_tag)
  end

  defp escape_for(?&), do: "&amp;"

  defp escape_for(?<), do: "&lt;"

  defp escape_for(?>), do: "&gt;"

  defp escape_for(?"), do: "&quot;"

  defp escape_for(?'), do: "&#39;"

  defp escape_for(c) when is_integer(c) and c <= 127, do: c

  defp escape_for(c) when is_integer(c) and c >= 128, do: << c :: utf8 >>

  defp escape_for(string) when is_binary(string) do
    string
    |> to_charlist()
    |> Enum.map(&escape_for/1)
  end

  defp escape(iodata) when is_list(iodata) do
    iodata
    |> :lists.flatten()
    |> Enum.map(&escape_for/1)
  end

  defp escape(other) when is_binary(other) do
    escape_for(other)
  end

  defp escape(c) when is_integer(c) do
    [escape_for(c)]
  end

  defp escape(other) do
    raise "Found `#{inspect(other)}` inside what should be an iolist"
  end

  @doc """
  Turns a list of tokens into an iolist which represents an HTML fragment.
  This fragment can be embedded directly into an HTML document.
  """
  def format_inner_as_iolist(tokens, opts) do
    highlight_tag = Keyword.get(opts, :highlight_tag, "span")
    Enum.map(tokens, &format_token(&1, highlight_tag))
  end

  @doc """
  Turns a list of tokens into an HTML fragment.
  This fragment can be embedded directly into an HTML document.
  """
  def format_inner_as_binary(tokens, opts) do
    tokens
    |> format_inner_as_iolist(opts)
    |> IO.iodata_to_binary
  end

  @doc """
  Turns a list of tokens into an iolist which represents an HTML fragment.
  This fragment can be embedded directly into an HTML document.
  """
  def format_as_iolist(tokens, opts \\ []) do
    css_class = Keyword.get(opts, :css_class, "highlight")
    inner = format_inner_as_iolist(tokens, opts)

    [
      ~S(<pre class="),
      css_class,
      ~S("><code>),
      inner,
      ~S(</code></pre>)
    ]
  end

  @doc """
  Turns a list of tokens into an HTML fragment.
  This fragment can be embedded directly into an HTML document.
  """
  def format_as_binary(tokens, opts \\ []) do
    tokens
    |> format_as_iolist(opts)
    |> IO.iodata_to_binary
  end

  @doc """
  Return the CSS stylesheet for a given style.
  """
  def stylesheet(style \\ :default_style, css_class \\ "highlight")

  def stylesheet(style, css_class) when is_atom(style) do
    stylesheet(apply(Makeup.Styles.HTML.StyleMap, style, []), css_class)
  end

  def stylesheet(style, css_class) do
    Makeup.Styles.HTML.Style.stylesheet(style, css_class)
  end

  @doc """
  Return a JavaScript snippet to highlight code on mouseover.
  This is "raw" javascript, and for inclusion in an HTML file
  it must be wrapped in a `<script>` tag.
  """
  def group_highlighter_javascript() do
    @group_highlight_js
  end
end