mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-30 23:08:00 +01:00
258 lines
5.2 KiB
Elixir
258 lines
5.2 KiB
Elixir
defmodule Textile.Lexer do
|
|
import NimbleParsec
|
|
import Textile.Helpers
|
|
import Textile.MarkupLexer
|
|
import Textile.UrlLexer
|
|
|
|
|
|
# Structural tags
|
|
|
|
|
|
# Literals enclosed via [== ==]
|
|
# Will never contain any markup
|
|
bracketed_literal =
|
|
ignore(string("[=="))
|
|
|> repeat(lookahead_not(string("==]")) |> utf8_char([]))
|
|
|> ignore(string("==]"))
|
|
|
|
unbracketed_literal =
|
|
ignore(string("=="))
|
|
|> repeat(lookahead_not(string("==")) |> utf8_char([]))
|
|
|> ignore(string("=="))
|
|
|
|
literal =
|
|
choice([
|
|
bracketed_literal,
|
|
unbracketed_literal
|
|
])
|
|
|> reduce({List, :to_string, []})
|
|
|> unwrap_and_tag(:literal)
|
|
|
|
blockquote_cite =
|
|
lookahead_not(string("\""))
|
|
|> choice([
|
|
literal |> reduce(:unwrap),
|
|
utf8_char([])
|
|
])
|
|
|> repeat()
|
|
|
|
# Blockquote opening tag with cite: [bq="the author"]
|
|
# Cite can contain bracketed literals or text
|
|
blockquote_open_cite =
|
|
ignore(string("[bq=\""))
|
|
|> concat(blockquote_cite)
|
|
|> ignore(string("\"]"))
|
|
|> reduce({List, :to_string, []})
|
|
|> unwrap_and_tag(:blockquote_open_cite)
|
|
|
|
# Blockquote opening tag
|
|
blockquote_open =
|
|
string("[bq]")
|
|
|> unwrap_and_tag(:blockquote_open)
|
|
|
|
# Blockquote closing tag
|
|
blockquote_close =
|
|
string("[/bq]")
|
|
|> unwrap_and_tag(:blockquote_close)
|
|
|
|
# Spoiler open tag
|
|
spoiler_open =
|
|
string("[spoiler]")
|
|
|> unwrap_and_tag(:spoiler_open)
|
|
|
|
# Spoiler close tag
|
|
spoiler_close =
|
|
string("[/spoiler]")
|
|
|> unwrap_and_tag(:spoiler_close)
|
|
|
|
|
|
# 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
|
|
])
|
|
|
|
|
|
# Links
|
|
|
|
|
|
{link_markup_start, link_markup_element} = markup_ending_in(string("\""))
|
|
|
|
link_url_stop =
|
|
choice([
|
|
string("*"),
|
|
string("@"),
|
|
string("^"),
|
|
string("~"),
|
|
string(".") |> concat(choice([space(), eos()])),
|
|
string("!") |> concat(choice([space(), eos()])),
|
|
string(",") |> concat(choice([space(), eos()])),
|
|
string("_") |> concat(choice([space(), eos()])),
|
|
string("?") |> concat(choice([space(), eos()])),
|
|
string(";") |> concat(choice([space(), eos()])),
|
|
space(),
|
|
eos()
|
|
])
|
|
|
|
link_contents_start =
|
|
choice([
|
|
image,
|
|
spoiler_open,
|
|
spoiler_close,
|
|
blockquote_open,
|
|
blockquote_open_cite,
|
|
blockquote_close,
|
|
literal,
|
|
link_markup_start
|
|
])
|
|
|
|
link_contents_element =
|
|
choice([
|
|
image,
|
|
spoiler_open,
|
|
spoiler_close,
|
|
blockquote_open,
|
|
blockquote_open_cite,
|
|
blockquote_close,
|
|
literal,
|
|
link_markup_element
|
|
])
|
|
|
|
link_contents =
|
|
optional(link_contents_start)
|
|
|> repeat(link_contents_element)
|
|
|
|
bracketed_link_end =
|
|
string("\":")
|
|
|> unwrap_and_tag(:link_end)
|
|
|> concat(
|
|
url_ending_in(string("]"))
|
|
|> ignore(string("]"))
|
|
|> unwrap_and_tag(:link_url)
|
|
)
|
|
|
|
bracketed_link =
|
|
string("[\"")
|
|
|> unwrap_and_tag(:link_start)
|
|
|> concat(link_contents)
|
|
|> concat(bracketed_link_end)
|
|
|
|
unbracketed_link_end =
|
|
string("\":")
|
|
|> unwrap_and_tag(:link_end)
|
|
|> concat(
|
|
url_ending_in(link_url_stop)
|
|
|> unwrap_and_tag(:link_url)
|
|
)
|
|
|
|
unbracketed_link =
|
|
string("\"")
|
|
|> unwrap_and_tag(:link_start)
|
|
|> concat(link_contents)
|
|
|> concat(unbracketed_link_end)
|
|
|
|
link =
|
|
choice([
|
|
bracketed_link,
|
|
unbracketed_link
|
|
])
|
|
|
|
|
|
# Textile
|
|
|
|
markup_ends =
|
|
choice([
|
|
spoiler_close,
|
|
blockquote_close,
|
|
eos()
|
|
])
|
|
|
|
{markup_start, markup_element} = markup_ending_in(markup_ends)
|
|
|
|
textile_default =
|
|
choice([
|
|
literal,
|
|
blockquote_open_cite |> optional(markup_start),
|
|
blockquote_open |> optional(markup_start),
|
|
blockquote_close,
|
|
spoiler_open |> optional(markup_start),
|
|
spoiler_close,
|
|
link,
|
|
image
|
|
])
|
|
|
|
textile_main =
|
|
choice([
|
|
textile_default,
|
|
markup_element
|
|
])
|
|
|
|
textile_start =
|
|
choice([
|
|
textile_default,
|
|
markup_start
|
|
])
|
|
|
|
textile =
|
|
optional(textile_start)
|
|
|> repeat(textile_main)
|
|
|> eos()
|
|
|
|
|
|
defparsec :lex, textile
|
|
end
|