diff --git a/lib/textile/helpers.ex b/lib/textile/helpers.ex index fcd05151..ecf54950 100644 --- a/lib/textile/helpers.ex +++ b/lib/textile/helpers.ex @@ -17,7 +17,7 @@ defmodule Textile.Helpers do def special_characters do choice([ space(), - utf8_char('#$%&(),-./:;<=?[\\]^`|~\'') + utf8_char('#$%&(),./:;<=?\\`|\'') ]) end diff --git a/lib/textile/lexer.ex b/lib/textile/lexer.ex index 72b1a472..e9272737 100644 --- a/lib/textile/lexer.ex +++ b/lib/textile/lexer.ex @@ -2,6 +2,7 @@ defmodule Textile.Lexer do import NimbleParsec import Textile.Helpers import Textile.MarkupLexer + import Textile.UrlLexer # Structural tags @@ -53,7 +54,67 @@ defmodule Textile.Lexer do string("[/spoiler]") |> unwrap_and_tag(:spoiler_close) - markup = markup_segment(eos()) - defparsec :markup, markup + # 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 end \ No newline at end of file diff --git a/lib/textile/markup_lexer.ex b/lib/textile/markup_lexer.ex index d77e8f7f..de3a20f1 100644 --- a/lib/textile/markup_lexer.ex +++ b/lib/textile/markup_lexer.ex @@ -118,12 +118,12 @@ defmodule Textile.MarkupLexer do b_sup_close, b_del_close, b_sub_close, - b_close, - i_close, ]) markup_closing_tags = choice([ + b_close, + i_close, strong_close, em_close, code_close, @@ -133,6 +133,14 @@ defmodule Textile.MarkupLexer do sub_close ]) + markup_tags = + choice([ + bracketed_markup_opening_tags, + bracketed_markup_closing_tags, + markup_opening_tags, + markup_closing_tags + ]) + markup_at_start = choice([ markup_opening_tags, @@ -142,12 +150,10 @@ defmodule Textile.MarkupLexer do markup_element = lookahead_not(ending_sequence) |> choice([ + bracketed_markup_closing_tags, + bracketed_markup_opening_tags |> lookahead_not(space()), special_characters() |> concat(markup_opening_tags), - bracketed_markup_opening_tags, - # utf8 char which is not a space followed by a closing tag followed by a special or the end - utf8_char([]) |> lookahead_not(space()) |> concat(markup_closing_tags) |> lookahead(choice([special_characters(), ending_sequence])), - utf8_char([]) |> concat(bracketed_markup_closing_tags), - literal, + markup_closing_tags |> choice([special_characters(), ending_sequence]), utf8_char([]) ]) diff --git a/lib/textile/url_lexer.ex b/lib/textile/url_lexer.ex new file mode 100644 index 00000000..443e74f1 --- /dev/null +++ b/lib/textile/url_lexer.ex @@ -0,0 +1,14 @@ +defmodule Textile.UrlLexer do + import NimbleParsec + + def url_ending_in(ending_sequence) do + protocol = + choice([ + string("/"), string("https://"), string("http://"), string("data:image/") + ]) + + protocol + |> repeat(lookahead_not(ending_sequence) |> utf8_char([])) + |> reduce({List, :to_string, []}) + end +end \ No newline at end of file