Packages
earmark
1.2.3
1.5.0-pre1
retired
1.5.0-pre
retired
1.4.49
retired
1.4.48
retired
1.4.47
retired
1.4.46
retired
1.4.45
retired
1.4.44
retired
1.4.43
retired
1.4.42
retired
1.4.41
retired
1.4.40
retired
1.4.39
retired
1.4.38
retired
1.4.37
retired
1.4.36
retired
1.4.35
retired
1.4.34
retired
1.4.33
retired
1.4.32
retired
1.4.31
retired
1.4.30
retired
1.4.29
retired
1.4.28
retired
1.4.27
retired
1.4.26
retired
1.4.25
retired
1.4.24
retired
1.4.23
retired
1.4.22
retired
1.4.21
retired
1.4.20
retired
1.4.19
retired
1.4.18
retired
1.4.17
retired
1.4.16
retired
1.4.16-pre2
retired
1.4.16-pre1
retired
1.4.16-pre
retired
1.4.15
retired
1.4.14
retired
1.4.13
retired
1.4.12
retired
1.4.10
retired
1.4.9
retired
1.4.8
retired
1.4.7
retired
1.4.6
retired
1.4.5
retired
1.4.4
retired
1.4.3
retired
1.4.2
retired
1.4.1
retired
1.4.0
retired
1.3.6
retired
1.3.5
retired
1.3.4
retired
1.3.3
retired
1.3.2
retired
1.3.1
retired
1.3.0
retired
1.2.6
retired
1.2.5
retired
1.2.4
retired
1.2.3
retired
1.2.2
retired
1.2.1
retired
1.2.0
retired
1.1.1
retired
1.1.0
retired
1.0.3
retired
1.0.2
retired
1.0.1
retired
1.0.0
retired
0.2.1
retired
0.2.0
retired
0.1.19
retired
0.1.18
retired
0.1.17
retired
0.1.16
retired
0.1.15
retired
0.1.14
retired
0.1.13
retired
0.1.12
retired
0.1.10
retired
0.1.9
retired
0.1.8
retired
0.1.7
retired
0.1.6
retired
0.1.5
retired
0.1.4
retired
0.1.3
retired
0.1.2
retired
0.1.1
retired
0.1.0
retired
Earmark is a pure-Elixir Markdown converter. It is intended to be used as a library (just call Earmark.as_html), but can also be used as a command-line tool (run mix escript.build first). Output generation is pluggable.
Retired package: Deprecated - Earmark is no longer maintained. Migrate to a replacement, for example MDEx (https://hex.pm/packages/mdex).
Current section
Files
Jump to
Current section
Files
lib/earmark/parser.ex
defmodule Earmark.Parser do
alias Earmark.Line
alias Earmark.Block
import Earmark.Message, only: [add_messages: 2]
@spec parse(list(String.t), %Earmark.Options{}, boolean) :: {Block.ts(), %{}}
def parse(text_lines), do: parse(text_lines, %Earmark.Options{}, false)
def parse(text_lines, options = %Earmark.Options{}, recursive) do
[ "" | text_lines ++ [""] ]
|> Line.scan_lines(options, recursive)
|> Block.parse(options)
end
################################################################
# Traverse the block list and extract the footnote definitions #
################################################################
# @spec handle_footnotes( Block.ts, %Earmark.Options{}, ( Block.ts,
def handle_footnotes(blocks, options, map_func) do
{ footnotes, blocks } = Enum.partition(blocks, &footnote_def?/1)
{ footnotes, undefined_footnotes } =
map_func.(blocks, &find_footnote_links/1)
|> List.flatten()
|> get_footnote_numbers(footnotes, options)
blocks = create_footnote_blocks(blocks, footnotes)
footnotes = map_func.(footnotes, &({&1.id, &1})) |> Enum.into(Map.new)
options1 = add_messages(options, undefined_footnotes)
{ blocks, footnotes, options1 }
end
@spec footnote_def?( Block.t )::boolean
defp footnote_def?(%Block.FnDef{}), do: true
defp footnote_def?(_block), do: false
@spec find_footnote_links(Block.t) :: list(String.t)
defp find_footnote_links(%Block.Para{lines: lines, lnb: lnb}) do
lines
|> Enum.zip(Stream.iterate(lnb, &(&1 + 1)))
|> Enum.flat_map(&extract_footnote_links/1)
end
defp find_footnote_links(%{blocks: blocks}) do
Enum.flat_map(blocks, &find_footnote_links/1)
end
defp find_footnote_links(_), do: []
@spec extract_footnote_links({String.t, number()}) :: list({String.t, number()})
defp extract_footnote_links({line, lnb}) do
Regex.scan(~r{\[\^([^\]]+)\]}, line)
|> Enum.map(&tl/1)
|> Enum.zip(Stream.cycle([lnb]))
end
@spec get_footnote_numbers( list({String.t, number()} ), Block.ts, %Earmark.Options{} ) :: Block.ts
def get_footnote_numbers(refs, footnotes, options) do
Enum.reduce(refs, {[], []}, fn({ref, lnb}, {defined, undefined}) ->
r = hd(ref)
case Enum.find(footnotes, &(&1.id == r)) do
note = %Block.FnDef{} -> number = length(defined) + options.footnote_offset
note = %Block.FnDef{ note | number: number }
{[ note | defined ], undefined}
_ -> {defined, [{:error, lnb, "footnote #{r} undefined, reference to it ignored"} | undefined]}
end
end)
end
@spec create_footnote_blocks(Block.ts, Block.ts) :: Block.ts
defp create_footnote_blocks(blocks, []), do: blocks
defp create_footnote_blocks(blocks, footnotes) do
lnb = footnotes
|> Stream.map(&(&1.lnb))
|> Enum.min()
footnote_block = %Block.FnList{blocks: Enum.sort_by(footnotes, &(&1.number)), lnb: lnb}
Enum.concat(blocks, [footnote_block])
end
end