maiku 0.6.1.maiku

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/lib/maruku.rb +141 -0
  2. data/lib/maruku/attributes.rb +175 -0
  3. data/lib/maruku/defaults.rb +71 -0
  4. data/lib/maruku/errors_management.rb +92 -0
  5. data/lib/maruku/ext/div.rb +133 -0
  6. data/lib/maruku/ext/math.rb +41 -0
  7. data/lib/maruku/ext/math/elements.rb +27 -0
  8. data/lib/maruku/ext/math/latex_fix.rb +12 -0
  9. data/lib/maruku/ext/math/mathml_engines/blahtex.rb +107 -0
  10. data/lib/maruku/ext/math/mathml_engines/itex2mml.rb +29 -0
  11. data/lib/maruku/ext/math/mathml_engines/none.rb +20 -0
  12. data/lib/maruku/ext/math/mathml_engines/ritex.rb +24 -0
  13. data/lib/maruku/ext/math/parsing.rb +119 -0
  14. data/lib/maruku/ext/math/to_html.rb +187 -0
  15. data/lib/maruku/ext/math/to_latex.rb +26 -0
  16. data/lib/maruku/helpers.rb +260 -0
  17. data/lib/maruku/input/charsource.rb +326 -0
  18. data/lib/maruku/input/extensions.rb +69 -0
  19. data/lib/maruku/input/html_helper.rb +189 -0
  20. data/lib/maruku/input/linesource.rb +111 -0
  21. data/lib/maruku/input/parse_block.rb +616 -0
  22. data/lib/maruku/input/parse_doc.rb +232 -0
  23. data/lib/maruku/input/parse_span_better.rb +746 -0
  24. data/lib/maruku/input/rubypants.rb +225 -0
  25. data/lib/maruku/input/type_detection.rb +147 -0
  26. data/lib/maruku/input_textile2/t2_parser.rb +163 -0
  27. data/lib/maruku/maruku.rb +33 -0
  28. data/lib/maruku/output/s5/fancy.rb +756 -0
  29. data/lib/maruku/output/s5/to_s5.rb +138 -0
  30. data/lib/maruku/output/to_html.rb +991 -0
  31. data/lib/maruku/output/to_latex.rb +590 -0
  32. data/lib/maruku/output/to_latex_entities.rb +367 -0
  33. data/lib/maruku/output/to_latex_strings.rb +64 -0
  34. data/lib/maruku/output/to_markdown.rb +164 -0
  35. data/lib/maruku/output/to_s.rb +56 -0
  36. data/lib/maruku/string_utils.rb +201 -0
  37. data/lib/maruku/structures.rb +167 -0
  38. data/lib/maruku/structures_inspect.rb +87 -0
  39. data/lib/maruku/structures_iterators.rb +61 -0
  40. data/lib/maruku/textile2.rb +1 -0
  41. data/lib/maruku/toc.rb +199 -0
  42. data/lib/maruku/usage/example1.rb +33 -0
  43. data/lib/maruku/version.rb +39 -0
  44. metadata +167 -0
@@ -0,0 +1,133 @@
1
+
2
+
3
+ #+-----------------------------------{.warning}------
4
+ #| this is the last warning!
5
+ #|
6
+ #| please, go away!
7
+ #|
8
+ #| +------------------------------------- {.menace} --
9
+ #| | or else terrible things will happen
10
+ #| +--------------------------------------------------
11
+ #+---------------------------------------------------
12
+
13
+ OpenDiv = /^[ ]{0,3}\+\-\-+\s*(\{([^{}]*|".*"|'.*')*\})?\s*\-*\s*$/
14
+ CloseDiv = /^[ ]{0,3}\=\-\-+\s*(\{([^{}]*|".*"|'.*')*\})?\s*\-*\s*$/
15
+ # note these are not enough for parsing the above example:
16
+ #OpenDiv = /^[ ]{0,3}\+\-\-+\s*(.*)$/
17
+ #CloseDiv = /^[ ]{0,3}\=\-\-+\s*(.*)$/
18
+ StartPipe = /^[ ]{0,3}\|(.*)$/ # $1 is rest of line
19
+ DecorativeClosing = OpenDiv
20
+
21
+ MaRuKu::In::Markdown::register_block_extension(
22
+ :regexp => OpenDiv,
23
+ :handler => lambda { |doc, src, context|
24
+ # return false if not doc.is_math_enabled?
25
+ first = src.shift_line
26
+ first =~ OpenDiv
27
+ ial_at_beginning = $1
28
+ ial_at_end = nil
29
+
30
+ lines = []
31
+ # if second line starts with "|"
32
+ if src.cur_line =~ StartPipe
33
+ # then we read until no more "|"
34
+ while src.cur_line && (src.cur_line =~ StartPipe)
35
+ content = $1
36
+ lines.push content
37
+ src.shift_line
38
+ end
39
+ if src.cur_line =~ DecorativeClosing
40
+ ial_at_end = $1
41
+ src.shift_line
42
+ end
43
+ else
44
+ # else we read until CloseDiv
45
+ divs_open = 1
46
+ while src.cur_line && (divs_open>0)
47
+ if src.cur_line =~ CloseDiv
48
+ divs_open -= 1
49
+ if divs_open == 0
50
+ ial_at_end = $1
51
+ src.shift_line
52
+ break
53
+ else
54
+ lines.push src.shift_line
55
+ end
56
+ else
57
+ if src.cur_line =~ OpenDiv
58
+ divs_open += 1
59
+ end
60
+ lines.push src.shift_line
61
+ end
62
+ end
63
+
64
+ if divs_open > 0
65
+ e = "At end of input, I still have #{divs_open} DIVs open."
66
+ doc.maruku_error(e, src, context)
67
+ return true
68
+ end
69
+ end
70
+
71
+ ial_at_beginning = nil unless
72
+ (ial_at_beginning&&ial_at_beginning.size > 0)
73
+ ial_at_end = nil unless (ial_at_end && ial_at_end.size > 0)
74
+
75
+ if ial_at_beginning && ial_at_end
76
+ e = "Found two conflicting IALs: #{ial_at_beginning.inspect} and #{ial_at_end.inspect}"
77
+ doc.maruku_error(e, src, context)
78
+ end
79
+
80
+ al_string = ial_at_beginning || ial_at_end
81
+ al = nil
82
+
83
+ if al_string =~ /^\{(.*)\}\s*$/
84
+ inside = $1
85
+ cs = MaRuKu::In::Markdown::SpanLevelParser::CharSource
86
+ al = al_string &&
87
+ doc.read_attribute_list(cs.new(inside), its_context=nil, break_on=[nil])
88
+ end
89
+
90
+ src = MaRuKu::In::Markdown::BlockLevelParser::LineSource.new(lines)
91
+ children = doc.parse_blocks(src)
92
+
93
+ context.push doc.md_div(children, al)
94
+ true
95
+ })
96
+
97
+
98
+ module MaRuKu; class MDElement
99
+
100
+ def md_div(children, al=nil)
101
+ type = label = num = nil
102
+ doc.refid2ref ||= {}
103
+ if al
104
+ al.each do |k, v|
105
+ case k
106
+ when :class
107
+ type = $1 if v =~ /^num_(\w*)/
108
+ when :id
109
+ label = v
110
+ end
111
+ end
112
+ end
113
+ if type
114
+ doc.refid2ref[type] ||= {}
115
+ num = doc.refid2ref[type].length + 1 || 1
116
+ end
117
+ e = self.md_el(:div, children, meta={:label => label, :type => type, :num => num}, al)
118
+ if type && label
119
+ doc.refid2ref[type].update({label => e})
120
+ end
121
+ e
122
+ end
123
+
124
+ end end
125
+
126
+
127
+ module MaRuKu; module Out; module HTML
128
+
129
+ def to_html_div
130
+ add_ws wrap_as_element('div')
131
+ end
132
+
133
+ end end end
@@ -0,0 +1,41 @@
1
+
2
+
3
+ require 'maruku/ext/math/elements'
4
+ require 'maruku/ext/math/parsing'
5
+ require 'maruku/ext/math/to_latex'
6
+ require 'maruku/ext/math/to_html'
7
+
8
+ require 'maruku/ext/math/mathml_engines/none'
9
+ require 'maruku/ext/math/mathml_engines/ritex'
10
+ require 'maruku/ext/math/mathml_engines/itex2mml'
11
+ require 'maruku/ext/math/mathml_engines/blahtex'
12
+
13
+
14
+ =begin maruku_doc
15
+ Attribute: math_enabled
16
+ Scope: global, document
17
+ Summary: Enables parsing of LaTeX math
18
+
19
+ To explicitly disable the math parsing:
20
+
21
+ Maruku.new(string, {:math_enabled => false})
22
+ {:ruby}
23
+
24
+ =end
25
+
26
+ MaRuKu::Globals[:math_enabled] = true
27
+
28
+
29
+ =begin maruku_doc
30
+ Attribute: math_numbered
31
+ Scope: global, document
32
+ Summary: Math openings which should be numerated
33
+
34
+ Array containing any of `'\\['`, `'\\begin{equation}'`, `'$$'`.
35
+
36
+ MaRuKu::Globals[:math_numbered] = ['\\[']
37
+
38
+ =end
39
+
40
+
41
+ MaRuKu::Globals[:math_numbered] = []
@@ -0,0 +1,27 @@
1
+ module MaRuKu; class MDElement
2
+
3
+ def md_inline_math(math)
4
+ self.md_el(:inline_math, [], meta={:math=>math})
5
+ end
6
+
7
+ def md_equation(math, label, numerate)
8
+ reglabel= /\\label\{(\w+)\}/
9
+ if math =~ reglabel
10
+ label = $1
11
+ math.gsub!(reglabel,'')
12
+ end
13
+ # puts "Found label = #{label} math #{math.inspect} "
14
+ num = nil
15
+ if (label || numerate) && @doc #take number
16
+ @doc.eqid2eq ||= {}
17
+ num = @doc.eqid2eq.size + 1
18
+ label = "eq#{num}" if not label # FIXME do id for document
19
+ end
20
+ e = self.md_el(:equation, [], meta={:math=>math, :label=>label,:num=>num})
21
+ if label && @doc #take number
22
+ @doc.eqid2eq[label] = e
23
+ end
24
+ e
25
+ end
26
+
27
+ end end
@@ -0,0 +1,12 @@
1
+ class String
2
+ # fix some LaTeX command-name clashes
3
+ def fix_latex
4
+ if #{html_math_engine} == 'itex2mml'
5
+ s = self.gsub("\\mathop{", "\\operatorname{")
6
+ s.gsub!(/\\begin\{svg\}.*?\\end\{svg\}/m, " ")
7
+ s.gsub("\\space{", "\\itexspace{")
8
+ else
9
+ self
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,107 @@
1
+
2
+ require 'tempfile'
3
+ require 'fileutils'
4
+ require 'digest/md5'
5
+ require 'pstore'
6
+
7
+ module MaRuKu; module Out; module HTML
8
+
9
+ PNG = Struct.new(:src,:depth,:height)
10
+
11
+ def convert_to_png_blahtex(kind, tex)
12
+ begin
13
+ FileUtils::mkdir_p get_setting(:html_png_dir)
14
+
15
+ # first, we check whether this image has already been processed
16
+ md5sum = Digest::MD5.hexdigest(tex+" params: ")
17
+ result_file = File.join(get_setting(:html_png_dir), md5sum+".txt")
18
+
19
+ if not File.exists?(result_file)
20
+ tmp_in = Tempfile.new('maruku_blahtex')
21
+ f = tmp_in.open
22
+ f.write tex
23
+ f.close
24
+
25
+ resolution = get_setting(:html_png_resolution)
26
+
27
+ options = "--png --use-preview-package --shell-dvipng 'dvipng -D #{resolution}' "
28
+ options += "--displaymath " if kind == :equation
29
+ options += ("--temp-directory '%s' " % get_setting(:html_png_dir))
30
+ options += ("--png-directory '%s'" % get_setting(:html_png_dir))
31
+
32
+ cmd = "blahtex #{options} < #{tmp_in.path} > #{result_file}"
33
+ #$stderr.puts "$ #{cmd}"
34
+ system cmd
35
+ tmp_in.delete
36
+ end
37
+
38
+ result = File.read(result_file)
39
+ if result.nil? || result.empty?
40
+ raise "Blahtex error: empty output"
41
+ end
42
+
43
+ doc = Document.new(result, {:respect_whitespace =>:all})
44
+ png = doc.root.elements[1]
45
+ if png.name != 'png'
46
+ raise "Blahtex error: \n#{doc}"
47
+ end
48
+ depth = png.elements['depth'] || (raise "No depth element in:\n #{doc}")
49
+ height = png.elements['height'] || (raise "No height element in:\n #{doc}")
50
+ md5 = png.elements['md5'] || (raise "No md5 element in:\n #{doc}")
51
+
52
+ depth = depth.text.to_f
53
+ height = height.text.to_f # XXX check != 0
54
+ md5 = md5.text
55
+
56
+ dir_url = get_setting(:html_png_url)
57
+ return PNG.new("#{dir_url}#{md5}.png", depth, height)
58
+ rescue Exception => e
59
+ maruku_error "Error: #{e}"
60
+ end
61
+ nil
62
+ end
63
+
64
+
65
+ def convert_to_mathml_blahtex(kind, tex)
66
+ @@BlahtexCache = PStore.new(get_setting(:latex_cache_file))
67
+
68
+ begin
69
+ @@BlahtexCache.transaction do
70
+ if @@BlahtexCache[tex].nil?
71
+ tmp_in = Tempfile.new('maruku_blahtex')
72
+ f = tmp_in.open
73
+ f.write tex
74
+ f.close
75
+ tmp_out = Tempfile.new('maruku_blahtex')
76
+
77
+ options = "--mathml"
78
+ cmd = "blahtex #{options} < #{tmp_in.path} > #{tmp_out.path}"
79
+ #$stderr.puts "$ #{cmd}"
80
+ system cmd
81
+ tmp_in.delete
82
+
83
+ result = nil
84
+ File.open(tmp_out.path) do |f| result=f.read end
85
+ puts result
86
+
87
+ @@BlahtexCache[tex] = result
88
+ end
89
+
90
+ blahtex = @@BlahtexCache[tex]
91
+ doc = Document.new(blahtex, {:respect_whitespace =>:all})
92
+ mathml = doc.root.elements['mathml']
93
+ if not mathml
94
+ maruku_error "Blahtex error: \n#{doc}"
95
+ return nil
96
+ else
97
+ return mathml
98
+ end
99
+ end
100
+
101
+ rescue Exception => e
102
+ maruku_error "Error: #{e}"
103
+ end
104
+ nil
105
+ end
106
+
107
+ end end end
@@ -0,0 +1,29 @@
1
+
2
+ module MaRuKu; module Out; module HTML
3
+
4
+ def convert_to_mathml_itex2mml(kind, tex)
5
+ begin
6
+ if not $itex2mml_parser
7
+ require 'itextomml'
8
+ $itex2mml_parser = Itex2MML::Parser.new
9
+ end
10
+
11
+ itex_method = {:equation=>:block_filter,:inline=>:inline_filter}
12
+
13
+ mathml = $itex2mml_parser.send(itex_method[kind], tex)
14
+ doc = Document.new(mathml, {:respect_whitespace =>:all}).root
15
+ return doc
16
+ rescue LoadError => e
17
+ maruku_error "Could not load package 'itex2mml'.\n"+ "Please install it." unless $already_warned_itex2mml
18
+ $already_warned_itex2mml = true
19
+ rescue REXML::ParseException => e
20
+ maruku_error "Invalid MathML TeX: \n#{add_tabs(tex,1,'tex>')}"+
21
+ "\n\n #{e.inspect}"
22
+ rescue
23
+ maruku_error "Could not produce MathML TeX: \n#{tex}"+
24
+ "\n\n #{e.inspect}"
25
+ end
26
+ nil
27
+ end
28
+
29
+ end end end
@@ -0,0 +1,20 @@
1
+ module MaRuKu; module Out; module HTML
2
+
3
+ def convert_to_mathml_none(kind, tex)
4
+ # You can: either return a REXML::Element
5
+ # return Element.new 'div'
6
+ # or return an empty array on error
7
+ # return []
8
+ # or have a string parsed by REXML:
9
+ tex = tex.gsub('&','&amp;')
10
+ mathml = "<code>#{tex}</code>"
11
+ return Document.new(mathml).root
12
+ end
13
+
14
+ def convert_to_png_none(kind, tex)
15
+ return nil
16
+ end
17
+
18
+
19
+ end end end
20
+
@@ -0,0 +1,24 @@
1
+ module MaRuKu; module Out; module HTML
2
+
3
+ def convert_to_mathml_ritex(kind, tex)
4
+ begin
5
+ if not $ritex_parser
6
+ require 'ritex'
7
+ $ritex_parser = Ritex::Parser.new
8
+ end
9
+
10
+ mathml = $ritex_parser.parse(tex.strip)
11
+ doc = Document.new(mathml, {:respect_whitespace =>:all}).root
12
+ return doc
13
+ rescue LoadError => e
14
+ maruku_error "Could not load package 'ritex'.\n"+
15
+ "Please install it using:\n"+
16
+ " $ gem install ritex\n\n"+e.inspect
17
+ rescue Racc::ParseError => e
18
+ maruku_error "Could not parse TeX: \n#{tex}"+
19
+ "\n\n #{e.inspect}"
20
+ end
21
+ nil
22
+ end
23
+
24
+ end end end
@@ -0,0 +1,119 @@
1
+ module MaRuKu
2
+
3
+ class MDDocument
4
+ # Hash equation id (String) to equation element (MDElement)
5
+ safe_attr_accessor :eqid2eq, Hash
6
+
7
+ def is_math_enabled?
8
+ get_setting :math_enabled
9
+ end
10
+ end
11
+ end
12
+
13
+
14
+ # Everything goes; takes care of escaping the "\$" inside the expression
15
+ RegInlineMath = /\${1}((?:[^\$]|\\\$)+)\$/
16
+
17
+ MaRuKu::In::Markdown::register_span_extension(
18
+ :chars => ?$,
19
+ :regexp => RegInlineMath,
20
+ :handler => lambda { |doc, src, con|
21
+ return false if not doc.is_math_enabled?
22
+
23
+ if m = src.read_regexp(RegInlineMath)
24
+ math = m.captures.compact.first
25
+ con.push doc.md_inline_math(math)
26
+ true
27
+ else
28
+ #puts "not math: #{src.cur_chars 10}"
29
+ false
30
+ end
31
+ }
32
+ )
33
+
34
+
35
+ MathOpen1 = Regexp.escape('\\begin{equation}')
36
+ MathClose1 = Regexp.escape('\\end{equation}')
37
+ MathOpen2 = Regexp.escape('\\[')
38
+ MathClose2 = Regexp.escape('\\]')
39
+ MathOpen3 = Regexp.escape('$$')
40
+ MathClose3 = Regexp.escape('$$')
41
+
42
+ EqLabel = /(?:\((\w+)\))/
43
+ EquationOpen = /#{MathOpen1}|#{MathOpen2}|#{MathOpen3}/
44
+ EquationClose = /#{MathClose1}|#{MathClose2}|#{MathClose3}/
45
+
46
+ # $1 is opening, $2 is tex
47
+ EquationStart = /^[ ]{0,3}(#{EquationOpen})(.*)$/
48
+ # $1 is tex, $2 is closing, $3 is tex
49
+ EquationEnd = /^(.*)(#{EquationClose})\s*#{EqLabel}?\s*$/
50
+ # $1 is opening, $2 is tex, $3 is closing, $4 is label
51
+ OneLineEquation = /^[ ]{0,3}(#{EquationOpen})(.*)(#{EquationClose})\s*#{EqLabel}?\s*$/
52
+
53
+ MaRuKu::In::Markdown::register_block_extension(
54
+ :regexp => EquationStart,
55
+ :handler => lambda { |doc, src, con|
56
+ return false if not doc.is_math_enabled?
57
+ first = src.shift_line
58
+ if first =~ OneLineEquation
59
+ opening, tex, closing, label = $1, $2, $3, $4
60
+ numerate = doc.get_setting(:math_numbered).include?(opening)
61
+ con.push doc.md_equation(tex, label, numerate)
62
+ else
63
+ first =~ EquationStart
64
+ opening, tex = $1, $2
65
+
66
+ numerate = doc.get_setting(:math_numbered).include?(opening)
67
+ label = nil
68
+ while true
69
+ if not src.cur_line
70
+ doc.maruku_error("Stream finished while reading equation\n\n"+
71
+ doc.add_tabs(tex,1,'$> '), src, con)
72
+ break
73
+ end
74
+ line = src.shift_line
75
+ if line =~ EquationEnd
76
+ tex_line, closing = $1, $2
77
+ label = $3 if $3
78
+ tex += tex_line + "\n"
79
+ break
80
+ else
81
+ tex += line + "\n"
82
+ end
83
+ end
84
+ con.push doc.md_equation(tex, label, numerate)
85
+ end
86
+ true
87
+ })
88
+
89
+
90
+ # This adds support for \eqref
91
+ RegEqrefLatex = /\\eqref\{(\w+)\}/
92
+ RegEqPar = /\(eq:(\w+)\)/
93
+ RegEqref = Regexp::union(RegEqrefLatex, RegEqPar)
94
+
95
+ MaRuKu::In::Markdown::register_span_extension(
96
+ :chars => [?\\, ?(],
97
+ :regexp => RegEqref,
98
+ :handler => lambda { |doc, src, con|
99
+ return false if not doc.is_math_enabled?
100
+ eqid = src.read_regexp(RegEqref).captures.compact.first
101
+ r = doc.md_el(:eqref, [], meta={:eqid=>eqid})
102
+ con.push r
103
+ true
104
+ }
105
+ )
106
+
107
+ # This adds support for \ref
108
+ RegRef = /\\ref\{(\w*)\}/
109
+ MaRuKu::In::Markdown::register_span_extension(
110
+ :chars => [?\\, ?(],
111
+ :regexp => RegRef,
112
+ :handler => lambda { |doc, src, con|
113
+ return false if not doc.is_math_enabled?
114
+ refid = src.read_regexp(RegRef).captures.compact.first
115
+ r = doc.md_el(:divref, [], meta={:refid=>refid})
116
+ con.push r
117
+ true
118
+ }
119
+ )