class Markdowner MAX_BARE_LINK = 50 def self.h(str) # .to_str is needed because this becomes a SafeBuffer, which breaks gsub # https://github.com/rails/rails/issues/1555 ERB::Util.h(str).to_str.gsub(/<(\/?)(em|u|strike)>/, '<\1\2>') end def self.markdown(string) lines = string.rstrip.split(/\r?\n/) out = "

" inpre = false lines.each do |line| # [ ][ ]blah ->

  blah
if line.match(/^( |\t)/) if !inpre out << "

"
        end

				out << ERB::Util.h(line) << "\n"
				inpre = true
				next
      elsif inpre
				out << "

\n

" inpre = false end line = self.h(line) # lines starting with > are quoted if m = line.match(/^>(.*)/) line = "

" << m[1] << "
" end lead = '\A|\s|[><]' trail = '[<>]|\z|\s' # *text* -> text line.gsub!(/(#{lead}|_|~)\*([^\* \t][^\*]*)\*(#{trail}|_|~)/) do |m| "#{$1}" << self.h($2) << "#{$3}" end # _text_ -> text line.gsub!(/(#{lead}|~)_([^_ \t][^_]*)_(#{trail}|~)/) do |m| "#{$1}" << self.h($2) << "#{$3}" end # ~~text~~ -> text (from reddit) line.gsub!(/(#{lead})\~\~([^~ \t][^~]*)\~\~(#{trail})/) do |m| "#{$1}" << self.h($2) << "#{$3}" end # [link text](http://url) -> link text line.gsub!(/(#{lead})\[([^\]]+)\]\((http(s?):\/\/[^\)]+)\)(#{trail})/i) do |m| "#{$1}" << self.h($2) << "#{$5}" end # find bare links that are not inside tags # http://blah -> chunk = "" intag = false outline = "" line.each_byte do |n| c = n.chr if intag outline << c if c == ">" intag = false next end else if c == "<" if chunk != "" outline << Markdowner._linkify_text(chunk) end chunk = "" intag = true outline << c else chunk << c end end end if chunk != "" outline << Markdowner._linkify_text(chunk) end out << outline << "
\n" end if inpre out << "" end out << "

" # multiple br's into a p out.gsub!(/
\n?
\n?/, "

") # collapse things out.gsub!(/
\n?<\/p>/, "

\n") out.gsub!(/

\n?
\n?/, "

") out.gsub!(/

\n?<\/p>/, "\n") out.gsub!(/

\n?

/, "\n

") out.gsub!(/<\/p>

/, "

\n

") out.strip end def self._linkify_text(chunk) chunk.gsub(/ (\A|\s|[:,]) (http(s?):\/\/|www\.) ([^\s]+)/ix) do |m| pre = $1 host_and_path = "#{$2 == "www." ? $2 : ""}#{$4}" post = $5 # remove some chars that might be with a url at the end but aren't # actually part of the url if m = host_and_path.match(/(.*)([,\?;\!\.]+)\z/) host_and_path = m[1] post = "#{m[2]}#{post}" end url = "http#{$3}://#{host_and_path}" url_text = host_and_path if url_text.length > 50 url_text = url_text[0 ... 50] << "..." end "#{pre}#{url_text}#{post}" end end end