Skip to content

Commit

Permalink
Merge pull request #132 from distler/master
Browse files Browse the repository at this point in the history
Unpantsed: a 40% speedup
  • Loading branch information
bhollis committed May 9, 2014
2 parents 066951d + 01219ea commit 7a70d54
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 8 deletions.
1 change: 0 additions & 1 deletion lib/maruku.rb
Expand Up @@ -89,7 +89,6 @@ class Maruku < MaRuKu::MDDocument; end
# Code for parsing Markdown span-level elements
require 'maruku/input/charsource'
require 'maruku/input/parse_span'
require 'maruku/input/rubypants'

require 'maruku/input/extensions'

Expand Down
97 changes: 90 additions & 7 deletions lib/maruku/input/parse_span.rb
Expand Up @@ -22,14 +22,16 @@ def parse_span(string, parent=nil)
def read_span(src, escaped, exit_on_chars=nil, exit_on_strings=nil)
escaped = Array(escaped)
con = SpanContext.new
c = d = nil
dquote_state = squote_state = :closed
c = d = prev_char = nil
while true
c = src.cur_char

# This is only an optimization which cuts 50% of the time used.
# (but you can't use a-zA-z in exit_on_chars)
if c && c =~ /a-zA-Z0-9/
if c && c =~ /[[:alnum:]]/
con.push_char src.shift_char
prev_char = c
next
end

Expand All @@ -49,7 +51,21 @@ def read_span(src, escaped, exit_on_chars=nil, exit_on_strings=nil)
if src.cur_chars_are " \n"
src.ignore_chars(3)
con.push_element md_br
prev_char = ' '
next
elsif src.cur_chars_are ' >>' # closing guillemettes
src.ignore_chars(3)
con.push_element md_entity('nbsp')
con.push_element md_entity('raquo')
elsif src.cur_chars(5) =~ / '\d\ds/ # special case: '80s
src.ignore_chars(2)
con.push_space
con.push_element md_entity('rsquo')
elsif src.cur_chars_are " '" # opening single-quote
src.ignore_chars(2)
con.push_space
con.push_element md_entity('lsquo')
squote_state = :open
else
src.ignore_char
con.push_space
Expand All @@ -70,9 +86,14 @@ def read_span(src, escaped, exit_on_chars=nil, exit_on_strings=nil)

case d = src.next_char
when '<' # guillemettes
src.ignore_chars(2)
con.push_char '<'
con.push_char '<'
if src.cur_chars_are '<< '
src.ignore_chars(3)
con.push_element md_entity('laquo')
con.push_element md_entity('nbsp')
else
src.ignore_chars(2)
con.push_element md_entity('laquo')
end
when '!'
if src.cur_chars_are '<!--'
read_inline_html(src, con)
Expand All @@ -97,6 +118,13 @@ def read_span(src, escaped, exit_on_chars=nil, exit_on_strings=nil)
con.push_char src.shift_char
end
end
when '>'
if src.next_char == '>'
src.ignore_chars(2)
con.push_element md_entity('raquo')
else
con.push_char src.shift_char
end
when "\\"
d = src.next_char
if d == "'"
Expand Down Expand Up @@ -195,9 +223,60 @@ def read_span(src, escaped, exit_on_chars=nil, exit_on_strings=nil)
[ exit_on_chars ? "#{exit_on_chars.inspect} or" : "" ],
src, con)
break
when '-' # dashes
if src.next_char == '-'
if src.cur_chars_are '---'
src.ignore_chars(3)
con.push_element md_entity('mdash')
else
src.ignore_chars(2)
con.push_element md_entity('ndash')
end
else
con.push_char src.shift_char
end
when '.' # ellipses
if src.cur_chars_are '...'
src.ignore_chars(3)
con.push_element md_entity('hellip')
elsif src.cur_chars_are '. . .'
src.ignore_chars(5)
con.push_element md_entity('hellip')
else
con.push_char src.shift_char
end
when '"'
if dquote_state == :closed
dquote_state = :open
src.ignore_char
con.push_element md_entity('ldquo')
else
dquote_state = :closed
src.ignore_char
con.push_element md_entity('rdquo')
end
when "'"
if src.cur_chars(4) =~ /'\d\ds/ # special case: '80s
src.ignore_char
con.push_element md_entity('rsquo')
elsif squote_state == :open
squote_state = :closed unless src.next_char =~ /[[:alpha:]]/
src.ignore_char
con.push_element md_entity('rsquo')
else
if prev_char =~ /[[:alpha:]]/
src.ignore_char
con.push_element md_entity('rsquo')
else
src.ignore_char
con.push_element md_entity('lsquo')
squote_state = :open
end
end
else # normal text
con.push_char src.shift_char
end # end case
prev_char = c
end # end while true

con.push_string_if_present
Expand All @@ -212,14 +291,16 @@ def read_span(src, escaped, exit_on_chars=nil, exit_on_strings=nil)
end
con.elements.shift if s.empty?
end

con.elements.shift if (con.elements.first.kind_of?(String) && con.elements.first.empty?)

# Remove final spaces
if (s = con.elements.last).kind_of? String
s.chop! if s[-1, 1] == ' '
con.elements.pop if s.empty?
end

educate(con.elements)
con.elements
end


Expand Down Expand Up @@ -449,7 +530,9 @@ def read_inline_code(src, con)

# Try to handle empty single-ticks
if num_ticks > 1 && !src.next_matches(/.*#{Regexp.escape(end_string)}/)
con.push_element(end_string) and return
con.push_element md_entity('ldquo')
src.ignore_chars(2)
return
end

code = read_simple(src, nil, nil, end_string)
Expand Down

0 comments on commit 7a70d54

Please sign in to comment.