2019-11-03 02:47:54 +01:00
|
|
|
defmodule Textile.Lexer do
|
|
|
|
import NimbleParsec
|
2019-11-03 21:32:55 +01:00
|
|
|
import Textile.Helpers
|
|
|
|
import Textile.MarkupLexer
|
2019-11-04 00:58:11 +01:00
|
|
|
import Textile.UrlLexer
|
2019-11-03 02:47:54 +01:00
|
|
|
|
|
|
|
|
2019-11-03 21:32:55 +01:00
|
|
|
# Structural tags
|
|
|
|
|
2019-11-03 02:47:54 +01:00
|
|
|
|
2019-11-03 21:32:55 +01:00
|
|
|
# Literals enclosed via [== ==]
|
|
|
|
# Will never contain any markup
|
2019-11-03 02:47:54 +01:00
|
|
|
bracketed_literal =
|
|
|
|
ignore(string("[=="))
|
|
|
|
|> repeat(lookahead_not(string("==]")) |> utf8_char([]))
|
|
|
|
|> ignore(string("==]"))
|
|
|
|
|> reduce({List, :to_string, []})
|
|
|
|
|> unwrap_and_tag(:bracketed_literal)
|
|
|
|
|
2019-11-03 21:32:55 +01:00
|
|
|
blockquote_cite =
|
|
|
|
lookahead_not(string("\""))
|
|
|
|
|> choice([
|
|
|
|
bracketed_literal |> reduce(:unwrap),
|
|
|
|
utf8_char([])
|
2019-11-03 02:47:54 +01:00
|
|
|
])
|
2019-11-03 21:32:55 +01:00
|
|
|
|> repeat()
|
2019-11-03 02:47:54 +01:00
|
|
|
|
2019-11-03 21:32:55 +01:00
|
|
|
# Blockquote opening tag with cite: [bq="the author"]
|
|
|
|
# Cite can contain bracketed literals or text
|
|
|
|
blockquote_open_cite =
|
2019-11-03 02:47:54 +01:00
|
|
|
ignore(string("[bq=\""))
|
2019-11-03 21:32:55 +01:00
|
|
|
|> concat(blockquote_cite)
|
2019-11-03 02:47:54 +01:00
|
|
|
|> ignore(string("\"]"))
|
|
|
|
|> reduce({List, :to_string, []})
|
2019-11-03 21:32:55 +01:00
|
|
|
|> unwrap_and_tag(:blockquote_open_cite)
|
2019-11-03 02:47:54 +01:00
|
|
|
|
2019-11-03 21:32:55 +01:00
|
|
|
# Blockquote opening tag
|
|
|
|
blockquote_open =
|
|
|
|
string("[bq]")
|
|
|
|
|> unwrap_and_tag(:blockquote_open)
|
2019-11-03 02:47:54 +01:00
|
|
|
|
2019-11-03 21:32:55 +01:00
|
|
|
# Blockquote closing tag
|
|
|
|
blockquote_close =
|
|
|
|
string("[/bq]")
|
|
|
|
|> unwrap_and_tag(:blockquote_close)
|
2019-11-03 02:47:54 +01:00
|
|
|
|
2019-11-03 21:32:55 +01:00
|
|
|
# Spoiler open tag
|
|
|
|
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 tag
|
|
|
|
spoiler_close =
|
|
|
|
string("[/spoiler]")
|
|
|
|
|> unwrap_and_tag(:spoiler_close)
|
2019-11-03 02:47:54 +01:00
|
|
|
|
|
|
|
|
2019-11-04 00:58:11 +01:00
|
|
|
# Images
|
|
|
|
|
|
|
|
|
|
|
|
image_url_with_title =
|
|
|
|
url_ending_in(string("("))
|
|
|
|
|> unwrap_and_tag(:image_url)
|
|
|
|
|> concat(
|
|
|
|
ignore(string("("))
|
|
|
|
|> repeat(utf8_char(not: ?)))
|
|
|
|
|> ignore(string(")"))
|
|
|
|
|> lookahead(string("!"))
|
|
|
|
|> reduce({List, :to_string, []})
|
|
|
|
|> unwrap_and_tag(:image_title)
|
|
|
|
)
|
|
|
|
|
|
|
|
image_url_without_title =
|
|
|
|
url_ending_in(string("!"))
|
|
|
|
|> unwrap_and_tag(:image_url)
|
|
|
|
|
|
|
|
image_url =
|
|
|
|
choice([
|
|
|
|
image_url_with_title,
|
|
|
|
image_url_without_title
|
|
|
|
])
|
|
|
|
|
|
|
|
bracketed_image_with_link =
|
|
|
|
ignore(string("[!"))
|
|
|
|
|> concat(image_url)
|
|
|
|
|> ignore(string("!:"))
|
|
|
|
|> concat(
|
|
|
|
url_ending_in(string("]"))
|
|
|
|
|> unwrap_and_tag(:image_link_url)
|
|
|
|
)
|
|
|
|
|
|
|
|
bracketed_image_without_link =
|
|
|
|
ignore(string("[!"))
|
|
|
|
|> concat(image_url)
|
|
|
|
|> ignore(string("!]"))
|
|
|
|
|
|
|
|
image_with_link =
|
|
|
|
ignore(string("!"))
|
|
|
|
|> concat(image_url)
|
|
|
|
|> ignore(string("!:"))
|
|
|
|
|> concat(
|
|
|
|
url_ending_in(space())
|
|
|
|
|> unwrap_and_tag(:image_link_url)
|
|
|
|
)
|
|
|
|
|
|
|
|
image_without_link =
|
|
|
|
ignore(string("!"))
|
|
|
|
|> concat(image_url)
|
|
|
|
|> ignore(string("!"))
|
|
|
|
|
|
|
|
image =
|
|
|
|
choice([
|
|
|
|
bracketed_image_with_link,
|
|
|
|
bracketed_image_without_link,
|
|
|
|
image_with_link,
|
|
|
|
image_without_link
|
|
|
|
])
|
|
|
|
|
|
|
|
defparsec :image, image
|
2019-11-03 02:47:54 +01:00
|
|
|
end
|