Skip to content

Commit

Permalink
Use Redcarpet 2 for markdown rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
nono committed Feb 26, 2012
1 parent ec1b7ec commit fbd2288
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 103 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Expand Up @@ -22,7 +22,7 @@ gem "mysql2", "~>0.3"
gem "nokogiri", "~>1.5"
gem "oauth2", "~>0.5"
gem "rinku", "~>1.2"
gem "redcarpet", "~>1.17"
gem "redcarpet", "~>2.1"
gem "hiredis", "~>0.3"
gem "redis", "~>2.2", :require => ["redis/connection/hiredis", "redis"]
gem "sanitize", "~>2.0"
Expand Down
4 changes: 2 additions & 2 deletions Gemfile.lock
Expand Up @@ -200,7 +200,7 @@ GEM
rake (0.9.2.2)
rdoc (3.12)
json (~> 1.4)
redcarpet (1.17.2)
redcarpet (2.1.0)
redis (2.2.2)
redis-activesupport (3.2.1)
activesupport (= 3.2.1)
Expand Down Expand Up @@ -309,7 +309,7 @@ DEPENDENCIES
oauth2 (~> 0.5)
pry-rails
rails (~> 3.2.1)
redcarpet (~> 1.17)
redcarpet (~> 2.1)
redis (~> 2.2)
redis-activesupport (~> 3.2)
rinku (~> 1.2)
Expand Down
8 changes: 4 additions & 4 deletions lib/ar_base_ext.rb
Expand Up @@ -29,17 +29,17 @@ def self.truncate_attr(attr, nb_words=80)
end
end

def self.wikify_attr(attr, *opts)
def self.wikify_attr(attr)
method = "wikify_#{attr}".to_sym
before_validation method
define_method method do
send("#{attr}=", wikify(send("wiki_#{attr}"), *opts))
send("#{attr}=", wikify(send "wiki_#{attr}"))
end
sanitize_attr attr
end

# Transform wiki syntax to HTML
def wikify(txt, *extensions)
LFMarkdown.new(txt, *extensions).to_html
def wikify(txt)
LFMarkdown.render(txt)
end
end
137 changes: 65 additions & 72 deletions lib/lfmarkdown.rb
Expand Up @@ -12,98 +12,91 @@
# * URL are automatically transformed in links
# * words with several underscores are left unchanged (no italics)
# * PHP Markdown Extra-style tables are supported
# * and some other extensions listed on http://www.pell.portland.or.us/~orc/Code/discount/#Language+extensions
# * and some other extensions
#
class LFMarkdown < Redcarpet
class LFMarkdown < Redcarpet::Render::HTML
PARSER_OPTIONS = {
:no_intra_emphasis => true,
:tables => true,
:fenced_code_blocks => true,
:autolink => true,
:strikethrough => true,
:superscript => true
}

def initialize(text, *extensions)
text ||= ''
@filter_styles = true
@filter_html = true
@autolink = true
@tables = true
@strikethrough = true
@hard_wrap = true
@no_intraemphasis = true
@xhtml = true
@generate_toc = true
@codemap = {}
super(text.dup, *extensions)
end
HTML_OPTIONS = {
:filter_html => true,
:no_styles => true,
:hard_wrap => true,
:xhtml => true
}

def to_html
extract_code
process_internal_wiki_links
process_wikipedia_links
ret = fix_heading_levels(super)
ret = fix_internal_links(ret)
ret = process_code(ret)
ret = add_toc_content(ret) if text.length > 5_000
ret
def self.render(text)
text ||= ""
html_toc = Redcarpet::Markdown.new(Redcarpet::Render::HTML_TOC)
toc = text.length > 5000 ? html_toc.render(text) : ""
toc = "<h2 id=\"sommaire\">Sommaire</h2>\n#{toc}" unless toc.blank?
markdown = Redcarpet::Markdown.new(self, PARSER_OPTIONS)
html = markdown.render(text)
toc + html
end

protected

LF_LINK_REGEXP = RUBY_VERSION.starts_with?('1.8') ? /\[\[\[([ '\.:\-\w]+)\]\]\]/ : /\[\[\[([ '\.:\-\p{Word}]+)\]\]\]/
WP_LINK_REGEXP = RUBY_VERSION.starts_with?('1.8') ? /\[\[([ '\.+:!\-\(\)\w]+)\]\]/ : /\[\[([ '\.+:!\-\(\)\p{Word}]+)\]\]/
def initialize(extensions={})
super extensions.merge(HTML_OPTIONS)
end

def process_internal_wiki_links
@text.gsub!(LF_LINK_REGEXP, '[\1](/wiki/\1 "Lien du wiki interne LinuxFr.org")')
def preprocess(full_document)
process_internal_wiki_links(full_document)
process_wikipedia_links(full_document)
full_document
end

def process_wikipedia_links
@text.gsub!(WP_LINK_REGEXP) do
word = $1
escaped = word.gsub(/\(|\)|'/) {|x| "\\#{x}" }
parts = word.split(":")
parts.shift if %w(en es eo de wikt).include?(parts.first)
"[#{parts.join ':'}](http://fr.wikipedia.org/wiki/#{escaped} \"Définition Wikipédia\")"
end
def block_code(code, lang)
colorized = Albino.new(code, lang || "text").colorize(:P => "nowrap")
"<pre><code class=\"#{lang}\">#{colorized}</code></pre>"
end

def fix_heading_levels(str)
str.gsub!(/<(\/?)h(\d)/) { |_| "<#{$1}h#{$2.to_i + 1}" }
str
def header(text, header_level)
@toc_count ||= -1
@toc_count += 1
l = header_level + 1
"<h#{l} id=\"toc_#{@toc_count}\">#{text}</h#{l}>\n"
end

def fix_internal_links(str)
str.gsub!(/(href|src)="https:\/\/#{MY_DOMAIN}\//) { |_| "#{$1}=\"http://#{MY_DOMAIN}/" }
str
def strikethrough(text)
"<s>#{ERB::Util.html_escape text}</s>"
end

# Code taken from gollum (http://github.com/github/gollum)
def extract_code
@text.gsub!(/^``` ?(.+?)\r?\n(.+?)\r?\n```\r?$/m) do
id = Digest::SHA1.hexdigest($2)
@codemap[id] = { :lang => $1, :code => $2 }
id
end
def link(link, title, content)
link.sub!("https://#{MY_DOMAIN}/", "http://#{MY_DOMAIN}/")
t = " title=\"#{title}\"" unless title.blank?
"<a href=\"#{URI.escape link}\"#{t}>#{content}</a>"
end

def process_code(data)
@codemap.each do |id, spec|
lang, code = spec[:lang], spec[:code]
if code.lines.all? { |line| line =~ /\A\r?\n\Z/ || line =~ /^( |\t)/ }
code.gsub!(/^( |\t)/m, '')
end
output = colorize_code(code, lang)
data.gsub!(id) { "<pre><code class=\"#{lang}\">#{output}</code></pre>" }
end
data
def normal_text(text)
text.gsub('« ', '«&nbsp;').
gsub(/ ([:;»!?])/, '&nbsp;\1').
gsub(' -- ', '—').
gsub('...', '…')
end

def colorize_code(code, lang)
Albino.new(code, lang).colorize(:P => "nowrap").html_safe
rescue Albino::ShellArgumentError
raise if lang == "text"
code = lang + code
lang = "text"
retry
protected

LF_LINK_REGEXP = RUBY_VERSION.starts_with?('1.8') ? /\[\[\[([ '\.:\-\w]+)\]\]\]/ : /\[\[\[([ '\.:\-\p{Word}]+)\]\]\]/
WP_LINK_REGEXP = RUBY_VERSION.starts_with?('1.8') ? /\[\[([ '\.+:!\-\(\)\w]+)\]\]/ : /\[\[([ '\.+:!\-\(\)\p{Word}]+)\]\]/

def process_internal_wiki_links(text)
text.gsub!(LF_LINK_REGEXP, '[\1](/wiki/\1 "Lien du wiki interne LinuxFr.org")')
end

def add_toc_content(str)
return str if toc_content.blank?
"<h2 id=\"sommaire\">Sommaire</h2>\n" + toc_content.force_encoding("UTF-8") + str
def process_wikipedia_links(text)
text.gsub!(WP_LINK_REGEXP) do
word = $1
escaped = word.gsub(/\(|\)|'/) {|x| "\\#{x}" }
parts = word.split(":")
parts.shift if %w(en es eo de wikt).include?(parts.first)
"[#{parts.join ':'}](http://fr.wikipedia.org/wiki/#{escaped} \"Définition Wikipédia\")"
end
end

end
58 changes: 34 additions & 24 deletions spec/lib/lfmarkdown_spec.rb
@@ -1,64 +1,75 @@
# encoding: UTF-8
require 'spec_helper'


describe LFMarkdown do
it "accepts simple wiki syntax" do
html = LFMarkdown.new("**gras** et _it_").to_html
html = LFMarkdown.render("**gras** et _it_")
html.should == "<p><strong>gras</strong> et <em>it</em></p>\n"
end

it "accepts the superscript syntax" do
html = LFMarkdown.render("1^er et 2^(ème)")
html.should == "<p>1<sup>er</sup> et 2<sup>ème</sup></p>\n"
end

it "accepts the strikethrough syntax" do
html = LFMarkdown.render("foo ~~not~~ baz")
html.should == "<p>foo <s>not</s> baz</p>\n"
end

it "links automatically URL" do
html = LFMarkdown.new("http://pierre.tramo.name/").to_html
html = LFMarkdown.render("http://pierre.tramo.name/")
html.should == "<p><a href=\"http://pierre.tramo.name/\">http://pierre.tramo.name/</a></p>\n"
end

it "transforms [[[]]] to internal wiki links" do
html = LFMarkdown.new("[[[Linux]]]").to_html
html = LFMarkdown.render("[[[Linux]]]")
html.should == "<p><a href=\"/wiki/Linux\" title=\"Lien du wiki interne LinuxFr.org\">Linux</a></p>\n"
end

it "transforms [[]] to wikipedia links" do
html = LFMarkdown.new("[[Linux]]").to_html
html = LFMarkdown.render("[[Linux]]")
html.should == "<p><a href=\"http://fr.wikipedia.org/wiki/Linux\" title=\"Définition Wikipédia\">Linux</a></p>\n"
end

it "transforms [[]] to wikipedia links, even with spaces and accents" do
html = LFMarkdown.new("[[Paul Erdős]]").to_html
html.should == "<p><a href=\"http://fr.wikipedia.org/wiki/Paul Erdős\" title=\"Définition Wikipédia\">Paul Erdős</a></p>\n"
html = LFMarkdown.render("[[Paul Erdős]]")
html.should == "<p><a href=\"http://fr.wikipedia.org/wiki/Paul%20Erd%C5%91s\" title=\"Définition Wikipédia\">Paul Erdős</a></p>\n"
end

it "transforms [[]] to wikipedia links even for categories (with : . and -)" do
html = LFMarkdown.new("[[Fichier:HTML5-logo.svg]]").to_html
html = LFMarkdown.render("[[Fichier:HTML5-logo.svg]]")
html.should == "<p><a href=\"http://fr.wikipedia.org/wiki/Fichier:HTML5-logo.svg\" title=\"Définition Wikipédia\">Fichier:HTML5-logo.svg</a></p>\n"
end

it "transforms [[]] to wikipedia links, even with parenthesis" do
html = LFMarkdown.new("[[Pogo_(danse)]]").to_html
html = LFMarkdown.render("[[Pogo_(danse)]]")
html.should == "<p><a href=\"http://fr.wikipedia.org/wiki/Pogo_(danse)\" title=\"Définition Wikipédia\">Pogo_(danse)</a></p>\n"
end

it "transforms [[]] to wikipedia links, even with quote" do
html = LFMarkdown.new("[[Loi d'Okun]]").to_html
html.should == "<p><a href=\"http://fr.wikipedia.org/wiki/Loi d'Okun\" title=\"Définition Wikipédia\">Loi d'Okun</a></p>\n"
html = LFMarkdown.render("[[Loi d'Okun]]")
html.should == "<p><a href=\"http://fr.wikipedia.org/wiki/Loi%20d'Okun\" title=\"Définition Wikipédia\">Loi d'Okun</a></p>\n"
end

it "transforms [[]] to wikipedia links, even with bang" do
html = LFMarkdown.new("[[Joomla!]]").to_html
html = LFMarkdown.render("[[Joomla!]]")
html.should == "<p><a href=\"http://fr.wikipedia.org/wiki/Joomla!\" title=\"Définition Wikipédia\">Joomla!</a></p>\n"
end

it "leaves underscored words unchanged" do
html = LFMarkdown.new("foo_bar_baz").to_html
html = LFMarkdown.render("foo_bar_baz")
html.should == "<p>foo_bar_baz</p>\n"
end

it "handles single line breaks" do
html = LFMarkdown.new("foo\nbar\n\nbaz").to_html
html = LFMarkdown.render("foo\nbar\n\nbaz")
html.should == "<p>foo<br/>\nbar</p>\n\n<p>baz</p>\n"
end

it "accepts heading levels from <h2> to <h4>" do
md = LFMarkdown.new <<EOS
md = LFMarkdown.render <<EOS
Title 1
=======
Expand All @@ -71,44 +82,43 @@
EOS
expected = <<EOS
<h2 id="toc_0">Title 1</h2>
<h3 id="toc_1">Title 2</h3>
<h4 id="toc_2">Title 3</h4>
<p>text</p>
EOS
md.to_html.should == expected
md.should == expected
end

it "colorizes code enclosed in ```" do
md = LFMarkdown.new <<EOS
md = LFMarkdown.render <<EOS
Mon joli code :
```ruby
class Ruby
end
```
EOS
md.to_html.should == "<p>Mon joli code :<br/>\n<pre><code class=\"ruby\"><span class=\"k\">class</span> <span class=\"nc\">Ruby</span>\n<span class=\"k\">end</span>\n</code></pre></p>\n"
md.should == "<p>Mon joli code :</p>\n<pre><code class=\"ruby\"><span class=\"k\">class</span> <span class=\"nc\">Ruby</span>\n<span class=\"k\">end</span>\n</code></pre>"
end

it "accepts code with utf-8 encoding" do
md = LFMarkdown.new <<EOS
md = LFMarkdown.render <<EOS
```bash
#!/bin/sh
# héhé
```
EOS
expect { md.to_html }.to_not raise_exception
md.to_html.encoding.should == Encoding.find("utf-8")
expect { md }.to_not raise_exception
md.encoding.should == Encoding.find("utf-8")
end

it 'accepts \" in code ' do
md = LFMarkdown.new <<EOS
md = LFMarkdown.render <<EOS
```perl
"Ceci \\" ne fonctionne pas"
```
EOS
md.to_html.should =~ /Ceci \\&quot; ne/
md.should =~ /Ceci \\&quot; ne/
end
end

0 comments on commit fbd2288

Please sign in to comment.