From ceb0931bb3a42cc2166ffeed07d1273730fc2cc6 Mon Sep 17 00:00:00 2001 From: Jacques Distler Date: Mon, 22 Jan 2007 11:34:51 -0600 Subject: [PATCH] Sync to lastest Maruku. Tweak to CSS stylesheet. --- lib/maruku/attributes.rb | 7 +- lib/maruku/defaults.rb | 6 + lib/maruku/errors_management.rb | 14 +- lib/maruku/ext/math.rb | 1 + lib/maruku/ext/math/mathml_engines/blahtex.rb | 108 +++++++++++ .../ext/math/mathml_engines/itex2mml.rb | 14 +- lib/maruku/ext/math/mathml_engines/none.rb | 10 +- lib/maruku/ext/math/mathml_engines/ritex.rb | 14 +- lib/maruku/ext/math/to_html.rb | 167 +++++++++++++----- lib/maruku/input/parse_block.rb | 3 +- lib/maruku/output/to_html.rb | 19 +- lib/maruku/output/to_latex.rb | 3 + lib/maruku/tests/benchmark.rb | 4 +- lib/maruku/tests/new_parser.rb | 16 +- public/stylesheets/instiki.css | 2 +- 15 files changed, 290 insertions(+), 98 deletions(-) create mode 100644 lib/maruku/ext/math/mathml_engines/blahtex.rb diff --git a/lib/maruku/attributes.rb b/lib/maruku/attributes.rb index 07736186..98ddc992 100644 --- a/lib/maruku/attributes.rb +++ b/lib/maruku/attributes.rb @@ -45,8 +45,11 @@ module MaRuKu; push [key, val] end def push_ref(ref_id); + raise "Bad :ref #{ref_id.inspect}" if not ref_id - push [:ref, ref_id] + push [:ref, ref_id+""] + +# p "Now ", self ######################################## end def push_class(val); raise "Bad :id #{val.inspect}" if not val @@ -81,6 +84,7 @@ module MaRuKu; module In; module Markdown; module SpanLevelParser [ "a =b", :throw, "No whitespace before `=`." ], [ "a= b", :throw, "No whitespace after `=`." ], + [ "a b", [[:ref, 'a'],[:ref, 'b']], "More than one ref" ], [ "a b c", [[:ref, 'a'],[:ref, 'b'],[:ref, 'c']], "More than one ref" ], [ "hello notfound", [[:ref, 'hello'],[:ref, 'notfound']]], @@ -129,6 +133,7 @@ module MaRuKu; module In; module Markdown; module SpanLevelParser # returns nil or an AttributeList def read_attribute_list(src, con, break_on_chars) + separators = break_on_chars + [?=,?\ ,?\t] escaped = Maruku::EscapedCharInQuotes diff --git a/lib/maruku/defaults.rb b/lib/maruku/defaults.rb index 2d4af38e..93dff0c1 100644 --- a/lib/maruku/defaults.rb +++ b/lib/maruku/defaults.rb @@ -30,6 +30,12 @@ Globals = { :code_background_color => '#fef', :code_show_spaces => false, :html_math_engine => 'itex2mml', #ritex, itex2mml, none + + :html_png_engine => 'none', + :html_png_dir => 'pngs', + :html_png_url => 'pngs/', + :html_png_resolution => 200, + :html_use_syntax => false, :on_error => :warning } diff --git a/lib/maruku/errors_management.rb b/lib/maruku/errors_management.rb index 387acea8..9aa8d3bc 100644 --- a/lib/maruku/errors_management.rb +++ b/lib/maruku/errors_management.rb @@ -70,13 +70,13 @@ module Errors def create_frame(s) n = 75 "\n" + - " "+"_"*n << "\n"<< - "| Maruku tells you:\n" << - "+"+"-"*n +"\n"+ - add_tabs(s,1,'| ') << "\n" << - "+" << "-"*n << "\n" << - add_tabs(caller[0, 5].join("\n"),1,'!') << "\n" << - "\\" << "_"*n << "\n" + " "+"_"*n + "\n"+ + "| Maruku tells you:\n" + + "+" + ("-"*n) +"\n"+ + add_tabs(s,1,'| ') + "\n" + + "+" + ("-"*n) + "\n" + + add_tabs(caller[0, 5].join("\n"),1,'!') + "\n" + + "\\" + ("_"*n) + "\n" end def describe_error(s,src,con) diff --git a/lib/maruku/ext/math.rb b/lib/maruku/ext/math.rb index 55b51ceb..759deb1f 100644 --- a/lib/maruku/ext/math.rb +++ b/lib/maruku/ext/math.rb @@ -8,3 +8,4 @@ require 'maruku/ext/math/to_html' require 'maruku/ext/math/mathml_engines/none' require 'maruku/ext/math/mathml_engines/ritex' require 'maruku/ext/math/mathml_engines/itex2mml' +require 'maruku/ext/math/mathml_engines/blahtex' diff --git a/lib/maruku/ext/math/mathml_engines/blahtex.rb b/lib/maruku/ext/math/mathml_engines/blahtex.rb new file mode 100644 index 00000000..2da34cbd --- /dev/null +++ b/lib/maruku/ext/math/mathml_engines/blahtex.rb @@ -0,0 +1,108 @@ + +require 'tempfile' +require 'fileutils' +require 'digest/md5' +require 'pstore' + +module MaRuKu; module Out; module HTML + + PNG = Struct.new(:src,:depth,:height) + + def convert_to_png_blahtex(kind, tex) + begin + FileUtils::mkdir_p MaRuKu::Globals[:html_png_dir] + + # first, we check whether this image has already been processed + md5sum = Digest::MD5.hexdigest(tex+" params: ") + result_file = File.join(MaRuKu::Globals[:html_png_dir], md5sum+".txt") + + if not File.exists?(result_file) + tmp_in = Tempfile.new('maruku_blahtex') + f = tmp_in.open + f.write tex + f.close + + resolution = get_setting(:html_png_resolution) + + options = "--png --use-preview-package --shell-dvipng 'dvipng -D #{resolution}' " + options += ("--png-directory '%s'" % MaRuKu::Globals[:html_png_dir]) + + cmd = "blahtex #{options} < #{tmp_in.path} > #{result_file}" + $stderr.puts "$ #{cmd}" + system cmd + tmp_in.delete + + end + + result = nil + f = File.open(result_file) + result = f.read + f.close + + + doc = Document.new(result, {:respect_whitespace =>:all}) + png = doc.root.elements[1] + if png.name != 'png' + maruku_error "Blahtex error: \n#{doc}" + return nil + end + depth = png.elements['depth'] || (raise "No depth element in:\n #{doc}") + height = png.elements['height'] || (raise "No height element in:\n #{doc}") + md5 = png.elements['md5'] || (raise "No md5 element in:\n #{doc}") + + depth = depth.text.to_f + height = height.text.to_f # XXX check != 0 + md5 = md5.text + + dir_url = MaRuKu::Globals[:html_png_url] + return PNG.new("#{dir_url}#{md5}.png", depth, height) + + rescue Exception => e + maruku_error "Error: #{e}" + end + nil + end + + BlahtexCache = PStore.new("blahtex_cache.pstore") + + def convert_to_mathml_blahtex(kind, tex) + begin + BlahtexCache.transaction do + if BlahtexCache[tex].nil? + tmp_in = Tempfile.new('maruku_blahtex') + f = tmp_in.open + f.write tex + f.close + tmp_out = Tempfile.new('maruku_blahtex') + + options = "--mathml" + cmd = "blahtex #{options} < #{tmp_in.path} > #{tmp_out.path}" + $stderr.puts "$ #{cmd}" + system cmd + tmp_in.delete + + result = nil + File.open(tmp_out.path) do |f| result=f.read end + puts result + + BlahtexCache[tex] = result + end + + blahtex = BlahtexCache[tex] + doc = Document.new(blahtex, {:respect_whitespace =>:all}) + mathml = doc.root.elements['mathml'] + if not mathml + maruku_error "Blahtex error: \n#{doc}" + return nil + else + return mathml + end + end + + rescue Exception => e + maruku_error "Error: #{e}" + end + nil + end + +end end end diff --git a/lib/maruku/ext/math/mathml_engines/itex2mml.rb b/lib/maruku/ext/math/mathml_engines/itex2mml.rb index 4f5be42e..164247fb 100644 --- a/lib/maruku/ext/math/mathml_engines/itex2mml.rb +++ b/lib/maruku/ext/math/mathml_engines/itex2mml.rb @@ -1,14 +1,16 @@ module MaRuKu; module Out; module HTML - def convert_to_mathml_itex2mml(tex, method) + def convert_to_mathml_itex2mml(kind, tex) begin if not $itex2mml_parser require 'itextomml' $itex2mml_parser = Itex2MML::Parser.new end - mathml = $itex2mml_parser.send(method, tex) + itex_method = {:equation=>:block_filter,:inline=>:inline_filter} + + mathml = $itex2mml_parser.send(itex_method[kind], tex) doc = Document.new(mathml, {:respect_whitespace =>:all}).root return doc rescue LoadError => e @@ -23,13 +25,5 @@ module MaRuKu; module Out; module HTML end nil end - - def to_html_inline_math_itex2mml - convert_to_mathml_itex2mml(self.math, :inline_filter) - end - - def to_html_equation_itex2mml - convert_to_mathml_itex2mml(self.math, :block_filter) - end end end end diff --git a/lib/maruku/ext/math/mathml_engines/none.rb b/lib/maruku/ext/math/mathml_engines/none.rb index 5fd04ec4..42f1df47 100644 --- a/lib/maruku/ext/math/mathml_engines/none.rb +++ b/lib/maruku/ext/math/mathml_engines/none.rb @@ -1,20 +1,20 @@ module MaRuKu; module Out; module HTML - def to_html_inline_math_none + def convert_to_mathml_none(kind, tex) # You can: either return a REXML::Element # return Element.new 'div' # or return an empty array on error # return [] # or have a string parsed by REXML: - tex = self.math - tex.gsub!('&','&') + tex = tex.gsub('&','&') mathml = "#{tex}" return Document.new(mathml).root end - def to_html_equation_none - return to_html_inline_math_none + def convert_to_png_none(kind, tex) + return nil end + end end end diff --git a/lib/maruku/ext/math/mathml_engines/ritex.rb b/lib/maruku/ext/math/mathml_engines/ritex.rb index fbb753b0..199eff5c 100644 --- a/lib/maruku/ext/math/mathml_engines/ritex.rb +++ b/lib/maruku/ext/math/mathml_engines/ritex.rb @@ -1,5 +1,6 @@ module MaRuKu; module Out; module HTML - def convert_to_mathml_ritex(tex) + + def convert_to_mathml_ritex(kind, tex) begin if not $ritex_parser require 'ritex' @@ -20,15 +21,4 @@ module MaRuKu; module Out; module HTML nil end - def to_html_inline_math_ritex - tex = self.math - mathml = convert_to_mathml_ritex(tex) - return mathml || [] - end - - def to_html_equation_ritex - tex = self.math - mathml = convert_to_mathml_ritex(tex) - return mathml || [] - end end end end diff --git a/lib/maruku/ext/math/to_html.rb b/lib/maruku/ext/math/to_html.rb index 5bc3fcab..105e6d7c 100644 --- a/lib/maruku/ext/math/to_html.rb +++ b/lib/maruku/ext/math/to_html.rb @@ -1,33 +1,37 @@ =begin maruku_doc +Extension: math Attribute: html_math_engine Scope: document, element Output: html -Summary: Select the rendering engine for math. +Summary: Select the rendering engine for MathML. Default: Select the rendering engine for math. -If you want to use your engine `foo`, then set: +If you want to use your custom engine `foo`, then set: HTML math engine: foo {:lang=markdown} and then implement two functions: - def to_html_inline_math_foo - # You can: either return a REXML::Element - # return Element.new 'div' - # or return an empty array on error - # return [] - # or have a string parsed by REXML: - tex = self.math - tex.gsub!('&','&') - mathml = "#{tex}" - return Document.new(mathml).root + def convert_to_mathml_foo(kind, tex) + ... end +=end - def to_html_equation_foo +=begin maruku_doc +Extension: math +Attribute: html_png_engine +Scope: document, element +Output: html +Summary: Select the rendering engine for math. +Default: + +Same thing as `html_math_engine`, only for PNG output. + + def convert_to_png_foo(kind, tex) # same thing ... end @@ -37,16 +41,6 @@ and then implement two functions: module MaRuKu; module Out; module HTML - def to_html_inline_math - s = get_setting(:html_math_engine) - method = "to_html_inline_math_#{s}".to_sym - if self.respond_to? method - self.send method || to_html_equation_none - else - puts "A method called #{method} should be defined." - return [] - end - end def add_class_to(el, cl) el.attributes['class'] = @@ -57,35 +51,112 @@ module MaRuKu; module Out; module HTML end end - def to_html_equation - s = get_setting(:html_math_engine) - method = "to_html_equation_#{s}".to_sym + # Creates an xml Mathml document of self.math + def render_mathml(kind, tex) + engine = get_setting(:html_math_engine) + method = "convert_to_mathml_#{engine}".to_sym if self.respond_to? method - mathml = self.send(method) || to_html_equation_none - div = create_html_element 'div' - add_class_to(div, 'maruku-equation') - if self.label # then numerate - span = Element.new 'span' - span.attributes['class'] = 'maruku-eq-number' - num = self.num - span << Text.new("(#{num})") - div << span - div.attributes['id'] = "eq:#{self.label}" - end - div << mathml - - source_div = Element.new 'div' - add_class_to(source_div, 'maruku-eq-tex') - code = to_html_equation_none - code.attributes['style'] = 'display: none' - source_div << code - div << source_div - div + mathml = self.send(method, kind, tex) + return mathml || convert_to_mathml_none(kind, tex) else puts "A method called #{method} should be defined." - return [] + return convert_to_mathml_none(kind, tex) end end + + # Creates an xml Mathml document of self.math + def render_png(kind, tex) + engine = get_setting(:html_png_engine) + method = "convert_to_png_#{engine}".to_sym + if self.respond_to? method + return self.send(method, kind, tex) + else + puts "A method called #{method} should be defined." + return nil + end + end + + def pixels_per_ex + if not $pixels_per_ex + x = render_png(:inline, "x") + $pixels_per_ex = x.height # + x.depth + end + $pixels_per_ex + end + + def adjust_png(png, use_depth) + src = png.src + + height_in_px = png.height + depth_in_px = png.depth + height_in_ex = height_in_px / pixels_per_ex + depth_in_ex = depth_in_px / pixels_per_ex + total_height_in_ex = height_in_ex + depth_in_ex + style = "" + style += "vertical-align: -#{depth_in_ex}ex;" if use_depth + style += "height: #{total_height_in_ex}ex;" + img = Element.new 'img' + img.attributes['src'] = src + img.attributes['style'] = style + img.attributes['alt'] = "equation" + img + end + + def to_html_inline_math + mathml = render_mathml(:inline, self.math) + png = render_png(:inline, self.math) + + span = create_html_element 'span' + add_class_to(span, 'maruku-inline') + + if mathml + add_class_to(mathml, 'maruku-mathml') + span << mathml + end + + if png + img = adjust_png(png, use_depth=true) + add_class_to(img, 'maruku-png') + span << img + end + span + + end + + def to_html_equation + mathml = render_mathml(:equation, self.math) + png = render_png(:equation, self.math) + + div = create_html_element 'div' + add_class_to(div, 'maruku-equation') + if self.label # then numerate + span = Element.new 'span' + span.attributes['class'] = 'maruku-eq-number' + num = self.num + span << Text.new("(#{num})") + div << span + div.attributes['id'] = "eq:#{self.label}" + end + + if mathml + add_class_to(mathml, 'maruku-mathml') + div << mathml + end + + if png + img = adjust_png(png, use_depth=false) + add_class_to(img, 'maruku-png') + div << img + end + + source_div = Element.new 'div' + add_class_to(source_div, 'maruku-eq-tex') + code = convert_to_mathml_none(:equation, self.math) + code.attributes['style'] = 'display: none' + source_div << code + div << source_div + div + end def to_html_eqref if eq = self.doc.eqid2eq[self.eqid] @@ -97,7 +168,7 @@ module MaRuKu; module Out; module HTML a else maruku_error "Cannot find equation #{self.eqid.inspect}" - Text.new "(#{self.eqid})" + Text.new "(eq:#{self.eqid})" end end diff --git a/lib/maruku/input/parse_block.rb b/lib/maruku/input/parse_block.rb index 3c1d1288..f142a300 100644 --- a/lib/maruku/input/parse_block.rb +++ b/lib/maruku/input/parse_block.rb @@ -59,6 +59,7 @@ module MaRuKu; module In; module Markdown; module BlockLevelParser when :ial m = InlineAttributeList.match src.shift_line content = m[1] || "" +# puts "Content: #{content.inspect}" src2 = CharSource.new(content, src) interpret_extension(src2, output, [nil]) when :ald @@ -468,7 +469,7 @@ module MaRuKu; module In; module Markdown; module BlockLevelParser end id = match[1]; url = match[2]; title = match[3]; - id = id.strip.downcase + id = id.strip.downcase.gsub(' ','_') hash = self.refs[id] = {:url=>url,:title=>title} diff --git a/lib/maruku/output/to_html.rb b/lib/maruku/output/to_html.rb index 8cf401d3..97c11fce 100644 --- a/lib/maruku/output/to_html.rb +++ b/lib/maruku/output/to_html.rb @@ -21,9 +21,6 @@ require 'rexml/document' -require 'rubygems' -require 'syntax' -require 'syntax/convertors/html' class String @@ -341,6 +338,12 @@ generated file. element = if use_syntax && lang begin + if not $syntax_loaded + require 'rubygems' + require 'syntax' + require 'syntax/convertors/html' + $syntax_loaded = true + end convertor = Syntax::Convertors::HTML.for_syntax lang # eliminate trailing newlines otherwise Syntax crashes @@ -351,6 +354,10 @@ generated file. pre = Document.new(html, {:respect_whitespace =>:all}).root pre.attributes['class'] = lang pre + rescue LoadError => e + maruku_error "Could not load package 'syntax'.\n"+ + "Please install it, for example using 'gem install syntax'." + to_html_code_using_pre(source) rescue Object => e maruku_error"Error while using the syntax library for code:\n#{source.inspect}"+ "Lang is #{lang} object is: \n"+ @@ -422,7 +429,8 @@ generated file. id = self.ref_id # if empty, use text if id.size == 0 - id = children.to_s.downcase + id = children.to_s.downcase.gsub(' ','_') + end if ref = @doc.refs[id] @@ -431,7 +439,8 @@ generated file. a.attributes['href'] = url if url a.attributes['title'] = title if title else - maruku_error"Could not find ref_id = #{id.inspect} for #{self.inspect}" + maruku_error "Could not find ref_id = #{id.inspect} for #{self.inspect}\n"+ + "Available refs are #{@doc.refs.keys.inspect}" tell_user "Not creating a link for ref_id = #{id.inspect}." return wrap_as_element('span') end diff --git a/lib/maruku/output/to_latex.rb b/lib/maruku/output/to_latex.rb index 0c91a176..84d24e44 100644 --- a/lib/maruku/output/to_latex.rb +++ b/lib/maruku/output/to_latex.rb @@ -78,8 +78,11 @@ You have to have these fonts installed -- and this can be a pain. If `latex_cjk` is specified, this is added to the preamble: + + + while the default is to add this: diff --git a/lib/maruku/tests/benchmark.rb b/lib/maruku/tests/benchmark.rb index 9854e10b..21d4a935 100644 --- a/lib/maruku/tests/benchmark.rb +++ b/lib/maruku/tests/benchmark.rb @@ -20,7 +20,7 @@ require 'maruku' -require 'bluecloth' +#require 'bluecloth' data = $stdin.read @@ -35,7 +35,7 @@ methods = [ [Maruku, :to_html], - [BlueCloth, :to_html], +# [BlueCloth, :to_html], [Maruku, :to_latex] ] diff --git a/lib/maruku/tests/new_parser.rb b/lib/maruku/tests/new_parser.rb index c2229552..6374398a 100644 --- a/lib/maruku/tests/new_parser.rb +++ b/lib/maruku/tests/new_parser.rb @@ -20,6 +20,7 @@ require 'maruku' +require 'maruku/ext/math' module MaRuKu; module Tests # 5 accented letters in italian, encoded as UTF-8 @@ -149,8 +150,10 @@ module MaRuKu; module Tests # links of the form [text][ref] ["\\[a]", ["[a]"], 'Escaping 1'], ["\\[a\\]", ["[a]"], 'Escaping 2'], - ["[a]", ["a"], 'Not a link'], - ["[a][]", [ md_link(["a"],'')], 'Empty link'], +# This is valid in the new Markdown version +# ["[a]", ["a"], 'Not a link'], + ["[a]", [ md_link(["a"],'')], 'Empty link'], + ["[a][]", ], ["[a][]b", [ md_link(["a"],''),'b'], 'Empty link'], ["[a\\]][]", [ md_link(["a]"],'')], 'Escape inside link'], @@ -256,11 +259,12 @@ module MaRuKu; module Tests ['[bar](/url/ "Title with "quotes" inside")', [md_im_link(["bar"],'/url/', 'Title with "quotes" inside')], "Link with quotes"], - - ['$20,000 and $30,000', ['$20,000 and $30,000'], 'Math: spaces'], + +# We dropped this idea +# ['$20,000 and $30,000', ['$20,000 and $30,000'], 'Math: spaces'], ['$20,000$', [md_inline_math('20,000')]], - ['$ 20,000$', ['$ 20,000$']], - ['$20,000 $ $20,000$', ['$20,000 $ ', md_inline_math('20,000')]], +# ['$ 20,000$', ['$ 20,000$']], +# ['$20,000 $ $20,000$', ['$20,000 $ ', md_inline_math('20,000')]], ["#{Maruku8}", [Maruku8], "Reading UTF-8"], ["#{AccIta1}", [AccIta8], "Converting ISO-8859-1 to UTF-8", {:encoding => 'iso-8859-1'}], diff --git a/public/stylesheets/instiki.css b/public/stylesheets/instiki.css index 2d6aedf3..f47bb065 100644 --- a/public/stylesheets/instiki.css +++ b/public/stylesheets/instiki.css @@ -308,7 +308,7 @@ a,li span { color:#000; } -a:hover,a.nav:hover { +a:hover,a.nav:hover, a:hover math { background-color:#000; color:#FFF; }