2019-11-03 02:47:54 +01:00
|
|
|
defmodule Textile.Lexer do
|
|
|
|
import NimbleParsec
|
|
|
|
|
2020-01-11 05:20:19 +01:00
|
|
|
space = utf8_char('\f \r\t\u00a0\u1680\u180e\u202f\u205f\u3000' ++ Enum.to_list(0x2000..0x200A))
|
2019-11-03 02:47:54 +01:00
|
|
|
|
2019-12-31 20:56:38 +01:00
|
|
|
extended_space =
|
|
|
|
choice([
|
|
|
|
space,
|
|
|
|
string("\n"),
|
|
|
|
eos()
|
|
|
|
])
|
|
|
|
|
|
|
|
space_token =
|
|
|
|
space
|
|
|
|
|> unwrap_and_tag(:space)
|
|
|
|
|
|
|
|
double_newline =
|
|
|
|
string("\n")
|
|
|
|
|> repeat(space)
|
|
|
|
|> string("\n")
|
|
|
|
|> reduce({List, :to_string, []})
|
|
|
|
|> unwrap_and_tag(:double_newline)
|
|
|
|
|
|
|
|
newline =
|
|
|
|
string("\n")
|
|
|
|
|> unwrap_and_tag(:newline)
|
|
|
|
|
2020-01-11 05:20:19 +01:00
|
|
|
link_ending_characters = utf8_char('@#$%&(),.:;<=?\\`|\'')
|
2019-11-03 21:32:55 +01:00
|
|
|
|
2020-01-11 05:20:19 +01:00
|
|
|
bracket_link_ending_characters = utf8_char('" []')
|
2019-12-31 20:56:38 +01:00
|
|
|
|
|
|
|
end_of_link =
|
|
|
|
choice([
|
|
|
|
concat(link_ending_characters, extended_space),
|
|
|
|
extended_space
|
|
|
|
])
|
2019-11-03 02:47:54 +01:00
|
|
|
|
|
|
|
bracketed_literal =
|
|
|
|
ignore(string("[=="))
|
|
|
|
|> repeat(lookahead_not(string("==]")) |> utf8_char([]))
|
|
|
|
|> ignore(string("==]"))
|
2019-12-16 06:59:25 +01:00
|
|
|
|
|
|
|
unbracketed_literal =
|
|
|
|
ignore(string("=="))
|
|
|
|
|> repeat(lookahead_not(string("==")) |> utf8_char([]))
|
|
|
|
|> ignore(string("=="))
|
|
|
|
|
|
|
|
literal =
|
|
|
|
choice([
|
|
|
|
bracketed_literal,
|
|
|
|
unbracketed_literal
|
|
|
|
])
|
2019-11-03 02:47:54 +01:00
|
|
|
|> reduce({List, :to_string, []})
|
2019-12-16 06:59:25 +01:00
|
|
|
|> unwrap_and_tag(:literal)
|
2019-11-03 02:47:54 +01:00
|
|
|
|
2019-12-31 20:56:38 +01:00
|
|
|
bq_cite_start =
|
|
|
|
string("[bq=\"")
|
|
|
|
|> unwrap_and_tag(:bq_cite_start)
|
2019-11-03 02:47:54 +01:00
|
|
|
|
2019-12-31 20:56:38 +01:00
|
|
|
bq_cite_open =
|
|
|
|
string("\"]")
|
|
|
|
|> unwrap_and_tag(:bq_cite_open)
|
2019-11-03 02:47:54 +01:00
|
|
|
|
2019-12-31 20:56:38 +01:00
|
|
|
bq_open =
|
2019-11-03 21:32:55 +01:00
|
|
|
string("[bq]")
|
2019-12-31 20:56:38 +01:00
|
|
|
|> unwrap_and_tag(:bq_open)
|
2019-11-03 02:47:54 +01:00
|
|
|
|
2019-12-31 20:56:38 +01:00
|
|
|
bq_close =
|
2019-11-03 21:32:55 +01:00
|
|
|
string("[/bq]")
|
2019-12-31 20:56:38 +01:00
|
|
|
|> unwrap_and_tag(:bq_close)
|
2019-11-03 02:47:54 +01:00
|
|
|
|
2019-11-03 21:32:55 +01:00
|
|
|
spoiler_open =
|
|
|
|
string("[spoiler]")
|
|
|
|
|> unwrap_and_tag(:spoiler_open)
|
2019-11-03 02:47:54 +01:00
|
|
|
|
2019-11-03 21:32:55 +01:00
|
|
|
spoiler_close =
|
|
|
|
string("[/spoiler]")
|
|
|
|
|> unwrap_and_tag(:spoiler_close)
|
2019-11-03 02:47:54 +01:00
|
|
|
|
2019-12-31 20:56:38 +01:00
|
|
|
image_url_scheme =
|
2019-11-04 00:58:11 +01:00
|
|
|
choice([
|
2019-12-31 20:56:38 +01:00
|
|
|
string("//"),
|
|
|
|
string("/"),
|
|
|
|
string("https://"),
|
|
|
|
string("http://")
|
2019-11-04 00:58:11 +01:00
|
|
|
])
|
|
|
|
|
2019-12-31 20:56:38 +01:00
|
|
|
link_url_scheme =
|
2019-11-04 00:58:11 +01:00
|
|
|
choice([
|
2019-12-31 20:56:38 +01:00
|
|
|
string("#"),
|
|
|
|
image_url_scheme
|
2019-11-04 00:58:11 +01:00
|
|
|
])
|
|
|
|
|
2020-01-11 19:57:58 +01:00
|
|
|
defparsec(
|
|
|
|
:unbracketed_url_inside,
|
|
|
|
choice([
|
|
|
|
string("(") |> parsec(:unbracketed_url_inside) |> string(")"),
|
|
|
|
lookahead_not(end_of_link) |> utf8_char([])
|
|
|
|
])
|
|
|
|
|> repeat()
|
|
|
|
)
|
|
|
|
|
2019-12-31 20:56:38 +01:00
|
|
|
unbracketed_url =
|
|
|
|
string(":")
|
|
|
|
|> concat(link_url_scheme)
|
2020-01-11 19:57:58 +01:00
|
|
|
|> parsec(:unbracketed_url_inside)
|
2019-11-04 01:10:05 +01:00
|
|
|
|
2019-12-31 20:56:38 +01:00
|
|
|
unbracketed_image_url =
|
|
|
|
unbracketed_url
|
|
|
|
|> reduce({List, :to_string, []})
|
|
|
|
|> unwrap_and_tag(:unbracketed_image_url)
|
2019-11-04 01:10:05 +01:00
|
|
|
|
2019-12-31 20:56:38 +01:00
|
|
|
unbracketed_link_url =
|
|
|
|
string("\"")
|
|
|
|
|> concat(unbracketed_url)
|
|
|
|
|> reduce({List, :to_string, []})
|
|
|
|
|> unwrap_and_tag(:unbracketed_link_url)
|
2019-11-27 22:07:22 +01:00
|
|
|
|
2019-12-31 20:56:38 +01:00
|
|
|
unbracketed_image =
|
|
|
|
ignore(string("!"))
|
|
|
|
|> concat(image_url_scheme)
|
|
|
|
|> repeat(utf8_char(not: ?!))
|
|
|
|
|> ignore(string("!"))
|
|
|
|
|> reduce({List, :to_string, []})
|
|
|
|
|> unwrap_and_tag(:unbracketed_image)
|
|
|
|
|> concat(optional(unbracketed_image_url))
|
2019-11-04 01:10:05 +01:00
|
|
|
|
2019-12-31 20:56:38 +01:00
|
|
|
bracketed_image =
|
|
|
|
ignore(string("[!"))
|
|
|
|
|> concat(image_url_scheme)
|
|
|
|
|> repeat(lookahead_not(string("!]")) |> utf8_char([]))
|
|
|
|
|> ignore(string("!]"))
|
|
|
|
|> reduce({List, :to_string, []})
|
|
|
|
|> unwrap_and_tag(:bracketed_image)
|
|
|
|
|> concat(optional(unbracketed_image_url))
|
2019-11-04 01:10:05 +01:00
|
|
|
|
2019-12-31 20:56:38 +01:00
|
|
|
link_delim =
|
|
|
|
string("\"")
|
|
|
|
|> unwrap_and_tag(:link_delim)
|
2019-11-04 01:10:05 +01:00
|
|
|
|
2019-12-31 20:56:38 +01:00
|
|
|
bracketed_link_open =
|
2019-11-04 01:10:05 +01:00
|
|
|
string("[\"")
|
2019-12-31 20:56:38 +01:00
|
|
|
|> unwrap_and_tag(:bracketed_link_open)
|
2019-11-04 01:10:05 +01:00
|
|
|
|
2019-12-31 20:56:38 +01:00
|
|
|
bracketed_link_url =
|
2019-11-04 01:10:05 +01:00
|
|
|
string("\":")
|
2019-12-31 20:56:38 +01:00
|
|
|
|> concat(link_url_scheme)
|
|
|
|
|> repeat(lookahead_not(bracket_link_ending_characters) |> utf8_char([]))
|
|
|
|
|> ignore(string("]"))
|
|
|
|
|> reduce({List, :to_string, []})
|
|
|
|
|> unwrap_and_tag(:bracketed_link_url)
|
|
|
|
|
|
|
|
bracketed_b_open = string("[**") |> unwrap_and_tag(:bracketed_b_open)
|
|
|
|
bracketed_i_open = string("[__") |> unwrap_and_tag(:bracketed_i_open)
|
|
|
|
bracketed_strong_open = string("[*") |> unwrap_and_tag(:bracketed_strong_open)
|
|
|
|
bracketed_em_open = string("[_") |> unwrap_and_tag(:bracketed_em_open)
|
|
|
|
bracketed_code_open = string("[@") |> unwrap_and_tag(:bracketed_code_open)
|
|
|
|
bracketed_ins_open = string("[+") |> unwrap_and_tag(:bracketed_ins_open)
|
|
|
|
bracketed_sup_open = string("[^") |> unwrap_and_tag(:bracketed_sup_open)
|
|
|
|
bracketed_del_open = string("[-") |> unwrap_and_tag(:bracketed_del_open)
|
|
|
|
bracketed_sub_open = string("[~") |> unwrap_and_tag(:bracketed_sub_open)
|
|
|
|
|
|
|
|
bracketed_b_close = string("**]") |> unwrap_and_tag(:bracketed_b_close)
|
|
|
|
bracketed_i_close = string("__]") |> unwrap_and_tag(:bracketed_i_close)
|
|
|
|
bracketed_strong_close = string("*]") |> unwrap_and_tag(:bracketed_strong_close)
|
|
|
|
bracketed_em_close = string("_]") |> unwrap_and_tag(:bracketed_em_close)
|
|
|
|
bracketed_code_close = string("@]") |> unwrap_and_tag(:bracketed_code_close)
|
|
|
|
bracketed_ins_close = string("+]") |> unwrap_and_tag(:bracketed_ins_close)
|
|
|
|
bracketed_sup_close = string("^]") |> unwrap_and_tag(:bracketed_sup_close)
|
|
|
|
bracketed_del_close = string("-]") |> unwrap_and_tag(:bracketed_del_close)
|
|
|
|
bracketed_sub_close = string("~]") |> unwrap_and_tag(:bracketed_sub_close)
|
|
|
|
|
|
|
|
b_delim = string("**") |> unwrap_and_tag(:b_delim)
|
|
|
|
i_delim = string("__") |> unwrap_and_tag(:i_delim)
|
|
|
|
strong_delim = string("*") |> unwrap_and_tag(:strong_delim)
|
|
|
|
em_delim = string("_") |> unwrap_and_tag(:em_delim)
|
|
|
|
code_delim = string("@") |> unwrap_and_tag(:code_delim)
|
|
|
|
ins_delim = string("+") |> unwrap_and_tag(:ins_delim)
|
|
|
|
sup_delim = string("^") |> unwrap_and_tag(:sup_delim)
|
|
|
|
sub_delim = string("~") |> unwrap_and_tag(:sub_delim)
|
|
|
|
|
2020-01-11 05:20:19 +01:00
|
|
|
del_delim =
|
|
|
|
lookahead_not(string("-"), choice([string("-"), string(">")])) |> unwrap_and_tag(:del_delim)
|
2019-12-31 20:56:38 +01:00
|
|
|
|
|
|
|
quicktxt =
|
|
|
|
utf8_char('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz*@_{}')
|
|
|
|
|> unwrap_and_tag(:quicktxt)
|
|
|
|
|
|
|
|
char =
|
|
|
|
utf8_char([])
|
|
|
|
|> unwrap_and_tag(:char)
|
2019-11-04 01:18:32 +01:00
|
|
|
|
2019-12-31 20:56:38 +01:00
|
|
|
textile =
|
2019-11-04 01:18:32 +01:00
|
|
|
choice([
|
2019-12-16 06:59:25 +01:00
|
|
|
literal,
|
2019-12-31 20:56:38 +01:00
|
|
|
double_newline,
|
|
|
|
newline,
|
|
|
|
space_token,
|
|
|
|
bq_cite_start,
|
|
|
|
bq_cite_open,
|
|
|
|
bq_open,
|
|
|
|
bq_close,
|
|
|
|
spoiler_open,
|
2019-11-04 01:18:32 +01:00
|
|
|
spoiler_close,
|
2019-12-31 20:56:38 +01:00
|
|
|
unbracketed_image,
|
|
|
|
bracketed_image,
|
|
|
|
bracketed_link_open,
|
|
|
|
bracketed_link_url,
|
|
|
|
unbracketed_link_url,
|
|
|
|
link_delim,
|
|
|
|
bracketed_b_open,
|
|
|
|
bracketed_i_open,
|
|
|
|
bracketed_strong_open,
|
|
|
|
bracketed_em_open,
|
|
|
|
bracketed_code_open,
|
|
|
|
bracketed_ins_open,
|
|
|
|
bracketed_sup_open,
|
|
|
|
bracketed_del_open,
|
|
|
|
bracketed_sub_open,
|
|
|
|
bracketed_b_close,
|
|
|
|
bracketed_i_close,
|
|
|
|
bracketed_strong_close,
|
|
|
|
bracketed_em_close,
|
|
|
|
bracketed_code_close,
|
|
|
|
bracketed_ins_close,
|
|
|
|
bracketed_sup_close,
|
|
|
|
bracketed_del_close,
|
|
|
|
bracketed_sub_close,
|
|
|
|
b_delim,
|
|
|
|
i_delim,
|
|
|
|
strong_delim,
|
|
|
|
em_delim,
|
|
|
|
code_delim,
|
|
|
|
ins_delim,
|
|
|
|
sup_delim,
|
|
|
|
del_delim,
|
|
|
|
sub_delim,
|
|
|
|
quicktxt,
|
|
|
|
char
|
2019-11-09 03:13:17 +01:00
|
|
|
])
|
2019-12-31 20:56:38 +01:00
|
|
|
|> repeat()
|
2019-11-04 01:18:32 +01:00
|
|
|
|> eos()
|
|
|
|
|
2020-01-11 05:20:19 +01:00
|
|
|
defparsec(:lex, textile)
|
2019-12-16 06:36:35 +01:00
|
|
|
end
|