Merge remote-tracking branch 'origin/master' into websequencediagrams

Conflicts:
	README.md
	lib/gollum.rb
	lib/gollum/markup.rb
This commit is contained in:
Corey Donohoe
2012-04-10 17:37:48 -07:00
544 changed files with 14948 additions and 43418 deletions
+183 -63
View File
@@ -1,7 +1,10 @@
require 'digest/sha1'
require 'cgi'
require 'pygments'
require 'base64'
module Gollum
class Markup
# Initialize a new Markup object.
#
@@ -11,13 +14,15 @@ module Gollum
def initialize(page)
@wiki = page.wiki
@name = page.filename
@data = page.raw_data
@version = page.version.id
@data = page.text_data
@version = page.version.id if page.version
@format = page.format
@dir = ::File.dirname(page.path)
@tagmap = {}
@codemap = {}
@texmap = {}
@wsdmap = {}
@premap = {}
end
# Render the content with Gollum wiki syntax on top of the file's own
@@ -25,13 +30,15 @@ module Gollum
#
# no_follow - Boolean that determines if rel="nofollow" is added to all
# <a> tags.
# encoding - Encoding Constant or String.
#
# Returns the formatted String content.
def render(no_follow = false)
sanitize_options = no_follow ?
HISTORY_SANITIZATION_OPTIONS :
SANITIZATION_OPTIONS
data = extract_tex(@data)
def render(no_follow = false, encoding = nil)
sanitize = no_follow ?
@wiki.history_sanitizer :
@wiki.sanitizer
data = extract_tex(@data.dup)
data = extract_code(data)
data = extract_wsd(data)
data = extract_tags(data)
@@ -44,10 +51,15 @@ module Gollum
data = %{<p class="gollum-error">#{e.message}</p>}
end
data = process_tags(data)
data = process_code(data)
data = process_wsd(data)
data = Sanitize.clean(data, sanitize_options)
data = process_code(data, encoding)
if sanitize || block_given?
doc = Nokogiri::HTML::DocumentFragment.parse(data)
doc = sanitize.clean_node!(doc) if sanitize
yield doc if block_given?
data = doc.to_html
end
data = process_tex(data)
data = process_wsd(data)
data.gsub!(/<p><\/p>/, '')
data
end
@@ -65,12 +77,14 @@ module Gollum
# Returns the placeholder'd String data.
def extract_tex(data)
data.gsub(/\\\[\s*(.*?)\s*\\\]/m) do
id = Digest::SHA1.hexdigest($1)
@texmap[id] = [:block, $1]
tag = CGI.escapeHTML($1)
id = Digest::SHA1.hexdigest(tag)
@texmap[id] = [:block, tag]
id
end.gsub(/\\\(\s*(.*?)\s*\\\)/m) do
id = Digest::SHA1.hexdigest($1)
@texmap[id] = [:inline, $1]
tag = CGI.escapeHTML($1)
id = Digest::SHA1.hexdigest(tag)
@texmap[id] = [:inline, tag]
id
end
end
@@ -84,13 +98,7 @@ module Gollum
def process_tex(data)
@texmap.each do |id, spec|
type, tex = *spec
out =
case type
when :block
%{<script type="math/tex; mode=display">#{tex}</script>}
when :inline
%{<script type="math/tex">#{tex}</script>}
end
out = %{<img src="#{::File.join(@wiki.base_path, '_tex.png')}?type=#{type}&data=#{Base64.encode64(tex).chomp}" alt="#{CGI.escapeHTML(tex)}">}
data.gsub!(id, out)
end
data
@@ -108,49 +116,57 @@ module Gollum
#
# Returns the placeholder'd String data.
def extract_tags(data)
data.gsub(/(.?)\[\[(.+?)\]\]([^\[]?)/m) do
data.gsub!(/(.?)\[\[(.+?)\]\]([^\[]?)/m) do
if $1 == "'" && $3 != "'"
"[[#{$2}]]#{$3}"
elsif $2.include?('][')
$&
if $2[0..4] == 'file:'
pre = $1
post = $3
parts = $2.split('][')
parts[0][0..4] = ""
link = "#{parts[1]}|#{parts[0].sub(/\.org/,'')}"
id = Digest::SHA1.hexdigest(link)
@tagmap[id] = link
"#{pre}#{id}#{post}"
else
$&
end
else
id = Digest::SHA1.hexdigest($2)
@tagmap[id] = $2
"#{$1}#{id}#{$3}"
end
end
data
end
# Process all tags from the tagmap and replace the placeholders with the
# final markup.
#
# data - The String data (with placeholders).
# no_follow - Boolean that determines if rel="nofollow" is added to all
# <a> tags.
#
# Returns the marked up String data.
def process_tags(data, no_follow = false)
def process_tags(data)
@tagmap.each do |id, tag|
data.gsub!(id, process_tag(tag, no_follow))
data.gsub!(id, process_tag(tag))
end
data
end
# Process a single tag into its final HTML form.
#
# tag - The String tag contents (the stuff inside the double
# tag - The String tag contents (the stuff inside the double
# brackets).
# no_follow - Boolean that determines if rel="nofollow" is added to all
# <a> tags.
#
# Returns the String HTML version of the tag.
def process_tag(tag, no_follow = false)
def process_tag(tag)
if html = process_image_tag(tag)
html
elsif html = process_file_link_tag(tag, no_follow)
elsif html = process_file_link_tag(tag)
html
else
process_page_link_tag(tag, no_follow)
process_page_link_tag(tag)
end
end
@@ -162,10 +178,12 @@ module Gollum
# if it is not.
def process_image_tag(tag)
parts = tag.split('|')
return if parts.size.zero?
name = parts[0].strip
path = if file = find_file(name)
::File.join @wiki.base_path, file.path
elsif name =~ /^https?:\/\/.+(jpg|png|gif|svg|bmp)$/
elsif name =~ /^https?:\/\/.+(jpg|png|gif|svg|bmp)$/i
name
end
@@ -243,15 +261,15 @@ module Gollum
# Attempt to process the tag as a file link tag.
#
# tag - The String tag contents (the stuff inside the double
# tag - The String tag contents (the stuff inside the double
# brackets).
# no_follow - Boolean that determines if rel="nofollow" is added to all
# <a> tags.
#
# Returns the String HTML if the tag is a valid file link tag or nil
# if it is not.
def process_file_link_tag(tag, no_follow = false)
def process_file_link_tag(tag)
parts = tag.split('|')
return if parts.size.zero?
name = parts[0].strip
path = parts[1] && parts[1].strip
path = if path && file = find_file(path)
@@ -262,49 +280,42 @@ module Gollum
nil
end
tag = if name && path && file
if name && path && file
%{<a href="#{::File.join @wiki.base_path, file.path}">#{name}</a>}
elsif name && path
%{<a href="#{path}">#{name}</a>}
else
nil
end
if tag && no_follow
tag.sub! /^<a/, '<a ref="nofollow"'
end
tag
end
# Attempt to process the tag as a page link tag.
#
# tag - The String tag contents (the stuff inside the double
# tag - The String tag contents (the stuff inside the double
# brackets).
# no_follow - Boolean that determines if rel="nofollow" is added to all
# <a> tags.
#
# Returns the String HTML if the tag is a valid page link tag or nil
# if it is not.
def process_page_link_tag(tag, no_follow = false)
def process_page_link_tag(tag)
parts = tag.split('|')
name = parts[0].strip
cname = Page.cname((parts[1] || parts[0]).strip)
tag = if name =~ %r{^https?://} && parts[1].nil?
parts.reverse! if @format == :mediawiki
name, page_name = *parts.compact.map(&:strip)
cname = @wiki.page_class.cname(page_name || name)
if name =~ %r{^https?://} && page_name.nil?
%{<a href="#{name}">#{name}</a>}
else
presence = "absent"
link_name = cname
page, extra = find_page_from_name(cname)
if page
link_name = Page.cname(page.name)
link_name = @wiki.page_class.cname(page.name)
presence = "present"
end
link = ::File.join(@wiki.base_path, CGI.escape(link_name))
%{<a class="internal #{presence}" href="#{link}#{extra}">#{name}</a>}
end
if tag && no_follow
tag.sub! /^<a/, '<a ref="nofollow"'
end
tag
end
# Find the given file in the repo.
@@ -326,7 +337,7 @@ module Gollum
#
# cname - The String canonical page name.
#
# Returns a Gollum::Page instance if a page is found, or an Array of
# Returns a Gollum::Page instance if a page is found, or an Array of
# [Gollum::Page, String extra] if a page without the extra anchor data
# is found.
def find_page_from_name(cname)
@@ -350,28 +361,58 @@ module Gollum
#
# Returns the placeholder'd String data.
def extract_code(data)
data.gsub(/^``` ?(.+?)\r?\n(.+?)\r?\n```\r?$/m) do
id = Digest::SHA1.hexdigest($2)
@codemap[id] = { :lang => $1, :code => $2 }
data.gsub!(/^``` ?([^\r\n]+)?\r?\n(.+?)\r?\n```\r?$/m) do
id = Digest::SHA1.hexdigest("#{$1}.#{$2}")
cached = check_cache(:code, id)
@codemap[id] = cached ?
{ :output => cached } :
{ :lang => $1, :code => $2 }
id
end
data
end
# Process all code from the codemap and replace the placeholders with the
# final HTML.
#
# data - The String data (with placeholders).
# data - The String data (with placeholders).
# encoding - Encoding Constant or String.
#
# Returns the marked up String data.
def process_code(data)
def process_code(data, encoding = nil)
return data if data.nil? || data.size.zero? || @codemap.size.zero?
blocks = []
@codemap.each do |id, spec|
lang = spec[:lang]
next if spec[:output] # cached
code = spec[:code]
if code.lines.all? { |line| line =~ /\A\r?\n\Z/ || line =~ /^( |\t)/ }
code.gsub!(/^( |\t)/m, '')
end
data.gsub!(id, Gollum::Albino.new(code, lang).colorize)
blocks << [spec[:lang], code]
end
highlighted = begin
encoding ||= 'utf-8'
blocks.map { |lang, code| Pygments.highlight(code, :lexer => lang, :options => {:encoding => encoding.to_s}) }
rescue ::RubyPython::PythonError
[]
end
@codemap.each do |id, spec|
body = spec[:output] || begin
if (body = highlighted.shift.to_s).size > 0
update_cache(:code, id, body)
body
else
"<pre><code>#{CGI.escapeHTML(spec[:code])}</code></pre>"
end
end
data.gsub!(id, body)
end
data
end
@@ -409,5 +450,84 @@ module Gollum
end
data
end
# Hook for getting the formatted value of extracted tag data.
#
# type - Symbol value identifying what type of data is being extracted.
# id - String SHA1 hash of original extracted tag data.
#
# Returns the String cached formatted data, or nil.
def check_cache(type, id)
end
# Hook for caching the formatted value of extracted tag data.
#
# type - Symbol value identifying what type of data is being extracted.
# id - String SHA1 hash of original extracted tag data.
# data - The String formatted value to be cached.
#
# Returns nothing.
def update_cache(type, id, data)
end
end
begin
require 'redcarpet'
class MarkupGFM < Markup
def render(no_follow = false, encoding = nil)
sanitize = no_follow ?
@wiki.history_sanitizer :
@wiki.sanitizer
data = extract_tex(@data.dup)
data = extract_code(data)
data = extract_tags(data)
if Gem::Version.new(Redcarpet::VERSION) > Gem::Version.new("1.17.2")
html_renderer = Redcarpet::Render::HTML.new({
:autolink => true,
:fenced_code_blocks => true,
:tables => true,
:strikethrough => true,
:lax_htmlblock => true,
:no_intraemphasis => true
})
markdown = Redcarpet::Markdown.new(html_renderer)
data = markdown.render(data)
else
flags = [
:autolink,
:fenced_code,
:tables,
:strikethrough,
:lax_htmlblock,
:no_intraemphasis
]
data = Redcarpet.new(data, *flags).to_html
end
data = process_tags(data)
data = process_code(data, encoding)
doc = Nokogiri::HTML::DocumentFragment.parse(data)
doc.search('pre').each do |node|
next unless lang = node['lang']
next unless lexer = Pygments::Lexer[lang]
text = node.inner_text
html = lexer.highlight(text)
node.replace(html)
end
doc = sanitize.clean_node!(doc) if sanitize
yield doc if block_given?
data = doc.to_html
data = process_tex(data)
data
end
end
rescue LoadError
MarkupGFM = Markup
end
end