maruku 0.5.8 → 0.5.9
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/maruku +22 -14
- data/lib/maruku/defaults.rb +2 -1
- data/lib/maruku/ext/div.rb +100 -0
- data/lib/maruku/ext/math.rb +1 -1
- data/lib/maruku/ext/math/mathml_engines/blahtex.rb +23 -25
- data/lib/maruku/input/parse_block.rb +4 -3
- data/lib/maruku/input/parse_span_better.rb +9 -4
- data/lib/maruku/input/type_detection.rb +5 -2
- data/lib/maruku/output/to_html.rb +14 -2
- data/lib/maruku/version.rb +1 -1
- data/tests/bugs/abbrev.md +1479 -0
- data/tests/bugs/html.md +29 -0
- data/tests/bugs/links.md +47 -0
- data/tests/unittest/divs/div1.md +204 -0
- data/tests/unittest/divs/div2.md +34 -0
- data/tests/unittest/divs/div3_nest.md +62 -0
- data/tests/unittest/email.md +1 -1
- data/tests/unittest/links.md +1 -1
- data/tests/unittest/pending/link.md +3 -3
- metadata +9 -2
data/bin/maruku
CHANGED
@@ -3,6 +3,11 @@
|
|
3
3
|
require 'maruku'
|
4
4
|
require 'optparse'
|
5
5
|
|
6
|
+
def cli_puts(s)
|
7
|
+
$stderr.puts(s) if MaRuKu::Globals[:verbose]
|
8
|
+
end
|
9
|
+
|
10
|
+
|
6
11
|
export = :html
|
7
12
|
break_on_error = false
|
8
13
|
using_math = false
|
@@ -26,7 +31,7 @@ opt = OptionParser.new do |opts|
|
|
26
31
|
MaRuKu::Globals[:html_math_output_png] = true
|
27
32
|
MaRuKu::Globals[:html_math_output_mathml] = false
|
28
33
|
MaRuKu::Globals[:html_png_engine] = s
|
29
|
-
|
34
|
+
cli_puts "Using png engine #{s}."
|
30
35
|
end
|
31
36
|
|
32
37
|
opts.on("-m", "--math-engine ENGINE", "Uses ENGINE to render MathML") do |s|
|
@@ -49,8 +54,7 @@ opt = OptionParser.new do |opts|
|
|
49
54
|
opts.on_tail("--inspect", "Shows the parsing result" ) do export = :inspect end
|
50
55
|
|
51
56
|
opts.on_tail("--version", "Show version") do
|
52
|
-
puts
|
53
|
-
exit
|
57
|
+
puts "Maruku #{MaRuKu::Version}"; exit
|
54
58
|
end
|
55
59
|
|
56
60
|
opts.on_tail("-h", "--help", "Show this message") do
|
@@ -68,27 +72,29 @@ rescue OptionParser::InvalidOption=>e
|
|
68
72
|
exit
|
69
73
|
end
|
70
74
|
|
75
|
+
|
71
76
|
if using_math
|
72
|
-
|
77
|
+
cli_puts "Using Math extensions."
|
73
78
|
require 'maruku/ext/math'
|
74
79
|
end
|
75
80
|
|
76
81
|
#p ARGV
|
77
82
|
#p MaRuKu::Globals
|
78
83
|
|
84
|
+
|
79
85
|
inputs =
|
80
86
|
# If we are given filenames, convert each file
|
81
87
|
if not ARGV.empty?
|
82
88
|
ARGV.map do |f|
|
83
89
|
# read file content
|
84
|
-
|
90
|
+
cli_puts "Reading from file #{f.inspect}."
|
85
91
|
[f, File.open(f,'r').read]
|
86
92
|
end
|
87
93
|
else
|
88
94
|
export = :html_frag if export == :html
|
89
95
|
export = :tex_frag if export == :tex
|
90
96
|
|
91
|
-
|
97
|
+
cli_puts "Reading from standard input."
|
92
98
|
[[nil, $stdin.read]]
|
93
99
|
end
|
94
100
|
|
@@ -100,7 +106,8 @@ inputs.each do |f, input|
|
|
100
106
|
|
101
107
|
t = Time.now
|
102
108
|
doc = Maruku.new(input, params)
|
103
|
-
|
109
|
+
|
110
|
+
cli_puts ("Parsing in %.2f seconds." % (Time.now-t))
|
104
111
|
|
105
112
|
out=""; suffix = "?"
|
106
113
|
t = Time.now
|
@@ -127,8 +134,9 @@ inputs.each do |f, input|
|
|
127
134
|
suffix='_s5slides.xhtml'
|
128
135
|
out = doc.to_s5({:content_only => false})
|
129
136
|
end
|
130
|
-
|
131
|
-
|
137
|
+
|
138
|
+
cli_puts("Rendering in %.2f seconds." % (Time.now-t))
|
139
|
+
|
132
140
|
# write to file or stdout
|
133
141
|
if f
|
134
142
|
|
@@ -141,19 +149,19 @@ inputs.each do |f, input|
|
|
141
149
|
end
|
142
150
|
|
143
151
|
if output_file == "-"
|
144
|
-
|
152
|
+
cli_puts "Writing to standard output"
|
145
153
|
$stdout.puts out
|
146
154
|
else
|
147
155
|
|
148
156
|
if not (export == :pdf)
|
149
|
-
|
157
|
+
cli_puts "Writing to #{output_file}"
|
150
158
|
File.open(output_file,'w') do |f| f.puts out end
|
151
159
|
else
|
152
|
-
|
160
|
+
cli_puts "Writing to #{job}.tex"
|
153
161
|
File.open("#{job}.tex",'w') do |f| f.puts out end
|
154
162
|
cmd = "pdflatex '#{job}.tex' -interaction=nonstopmode "+
|
155
163
|
"'-output-directory=#{dir}' "
|
156
|
-
|
164
|
+
cli_puts "maruku: executing $ #{cmd}"
|
157
165
|
# run twice for cross references
|
158
166
|
system cmd
|
159
167
|
system cmd
|
@@ -161,7 +169,7 @@ inputs.each do |f, input|
|
|
161
169
|
|
162
170
|
end
|
163
171
|
else # write to stdout
|
164
|
-
|
172
|
+
cli_puts "Writing to standard output"
|
165
173
|
$stdout.puts out
|
166
174
|
end
|
167
175
|
end
|
data/lib/maruku/defaults.rb
CHANGED
@@ -42,11 +42,12 @@ Globals = {
|
|
42
42
|
:html_png_dir => 'pngs',
|
43
43
|
:html_png_url => 'pngs/',
|
44
44
|
:html_png_resolution => 200,
|
45
|
-
|
45
|
+
|
46
46
|
:html_use_syntax => false,
|
47
47
|
|
48
48
|
:latex_use_listings => false,
|
49
49
|
:latex_cjk => false,
|
50
|
+
:latex_cache_file => "blahtex_cache.pstore", # cache file for blahtex filter
|
50
51
|
|
51
52
|
:debug_keep_ials => false,
|
52
53
|
:doc_prefix => ''
|
@@ -0,0 +1,100 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
OpenDiv = /^[ ]{0,3}\+\-\-+\s*([^\s-]*)\s*\-*\s*$/
|
4
|
+
CloseDiv = /^[ ]{0,3}\=\-\-+\s*([^\s-]*)\s*\-*\s*$/
|
5
|
+
StartPipe = /^[ ]{0,3}\|(.*)$/ # $1 is rest of line
|
6
|
+
DecorativeClosing = OpenDiv
|
7
|
+
|
8
|
+
MaRuKu::In::Markdown::register_block_extension(
|
9
|
+
:regexp => OpenDiv,
|
10
|
+
:handler => lambda { |doc, src, context|
|
11
|
+
# return false if not doc.is_math_enabled?
|
12
|
+
first = src.shift_line
|
13
|
+
first =~ OpenDiv
|
14
|
+
ial_at_beginning = $1
|
15
|
+
ial_at_end = nil
|
16
|
+
|
17
|
+
lines = []
|
18
|
+
# if second line starts with "|"
|
19
|
+
if src.cur_line =~ StartPipe
|
20
|
+
# then we read until no more "|"
|
21
|
+
while src.cur_line && (src.cur_line =~ StartPipe)
|
22
|
+
content = $1
|
23
|
+
lines.push content
|
24
|
+
src.shift_line
|
25
|
+
end
|
26
|
+
if src.cur_line =~ DecorativeClosing
|
27
|
+
ial_at_end = $1
|
28
|
+
src.shift_line
|
29
|
+
end
|
30
|
+
else
|
31
|
+
# else we read until CloseDiv
|
32
|
+
divs_open = 1
|
33
|
+
while src.cur_line && (divs_open>0)
|
34
|
+
if src.cur_line =~ CloseDiv
|
35
|
+
divs_open -= 1
|
36
|
+
if divs_open == 0
|
37
|
+
ial_at_end = $1
|
38
|
+
src.shift_line
|
39
|
+
break
|
40
|
+
else
|
41
|
+
lines.push src.shift_line
|
42
|
+
end
|
43
|
+
else
|
44
|
+
if src.cur_line =~ OpenDiv
|
45
|
+
divs_open += 1
|
46
|
+
end
|
47
|
+
lines.push src.shift_line
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
if divs_open > 0
|
52
|
+
e = "At end of input, I still have #{divs_open} DIVs open."
|
53
|
+
doc.maruku_error(e, src, context)
|
54
|
+
return true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
ial_at_beginning = nil unless
|
59
|
+
(ial_at_beginning&&ial_at_beginning.size > 0)
|
60
|
+
ial_at_end = nil unless (ial_at_end && ial_at_end.size > 0)
|
61
|
+
|
62
|
+
if ial_at_beginning && ial_at_end
|
63
|
+
e = "Found two conflicting IALs: #{ial_at_beginning.inspect} and #{ial_at_end.inspect}"
|
64
|
+
doc.maruku_error(e, src, context)
|
65
|
+
end
|
66
|
+
|
67
|
+
al_string = ial_at_beginning || ial_at_end
|
68
|
+
al = nil
|
69
|
+
|
70
|
+
if al_string =~ /^\{(.*)\}$/
|
71
|
+
inside = $1
|
72
|
+
cs = MaRuKu::In::Markdown::SpanLevelParser::CharSource
|
73
|
+
al = al_string &&
|
74
|
+
doc.read_attribute_list(cs.new(inside), its_context=nil, break_on=[nil])
|
75
|
+
end
|
76
|
+
|
77
|
+
src = MaRuKu::In::Markdown::BlockLevelParser::LineSource.new(lines)
|
78
|
+
children = doc.parse_blocks(src)
|
79
|
+
|
80
|
+
context.push doc.md_div(children, al)
|
81
|
+
true
|
82
|
+
})
|
83
|
+
|
84
|
+
|
85
|
+
module MaRuKu; class MDElement
|
86
|
+
|
87
|
+
def md_div(children, a=nil)
|
88
|
+
self.md_el(:div, children, meta={}, a)
|
89
|
+
end
|
90
|
+
|
91
|
+
end end
|
92
|
+
|
93
|
+
|
94
|
+
module MaRuKu; module Out; module HTML
|
95
|
+
|
96
|
+
def to_html_div
|
97
|
+
add_ws wrap_as_element('div')
|
98
|
+
end
|
99
|
+
|
100
|
+
end end end
|
data/lib/maruku/ext/math.rb
CHANGED
@@ -15,36 +15,34 @@ module MaRuKu; module Out; module HTML
|
|
15
15
|
# first, we check whether this image has already been processed
|
16
16
|
md5sum = Digest::MD5.hexdigest(tex+" params: ")
|
17
17
|
result_file = File.join(MaRuKu::Globals[:html_png_dir], md5sum+".txt")
|
18
|
-
|
18
|
+
|
19
19
|
if not File.exists?(result_file)
|
20
20
|
tmp_in = Tempfile.new('maruku_blahtex')
|
21
|
-
|
21
|
+
f = tmp_in.open
|
22
22
|
f.write tex
|
23
23
|
f.close
|
24
|
-
|
24
|
+
|
25
25
|
resolution = get_setting(:html_png_resolution)
|
26
|
-
|
27
|
-
options = "--png --use-preview-package --shell-dvipng 'dvipng -D #{resolution}' "
|
26
|
+
|
27
|
+
options = "--png --use-preview-package --shell-dvipng '/usr/bin/dvipng -D #{resolution}' "
|
28
|
+
options += ("--temp-directory '%s' " % MaRuKu::Globals[:html_png_dir])
|
28
29
|
options += ("--png-directory '%s'" % MaRuKu::Globals[:html_png_dir])
|
29
|
-
|
30
|
+
|
30
31
|
cmd = "blahtex #{options} < #{tmp_in.path} > #{result_file}"
|
31
|
-
|
32
|
-
|
32
|
+
#$stderr.puts "$ #{cmd}"
|
33
|
+
system cmd
|
33
34
|
tmp_in.delete
|
34
|
-
|
35
35
|
end
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
37
|
+
result = File.read(result_file)
|
38
|
+
if result.nil? || result.empty?
|
39
|
+
raise "Blahtex error: empty output"
|
40
|
+
end
|
41
|
+
|
43
42
|
doc = Document.new(result, {:respect_whitespace =>:all})
|
44
43
|
png = doc.root.elements[1]
|
45
44
|
if png.name != 'png'
|
46
|
-
|
47
|
-
return nil
|
45
|
+
raise "Blahtex error: \n#{doc}"
|
48
46
|
end
|
49
47
|
depth = png.elements['depth'] || (raise "No depth element in:\n #{doc}")
|
50
48
|
height = png.elements['height'] || (raise "No height element in:\n #{doc}")
|
@@ -56,19 +54,19 @@ module MaRuKu; module Out; module HTML
|
|
56
54
|
|
57
55
|
dir_url = MaRuKu::Globals[:html_png_url]
|
58
56
|
return PNG.new("#{dir_url}#{md5}.png", depth, height)
|
59
|
-
|
60
57
|
rescue Exception => e
|
61
58
|
maruku_error "Error: #{e}"
|
62
59
|
end
|
63
60
|
nil
|
64
61
|
end
|
65
62
|
|
66
|
-
|
67
|
-
|
63
|
+
|
68
64
|
def convert_to_mathml_blahtex(kind, tex)
|
65
|
+
@@BlahtexCache = PStore.new(MaRuKu::Globals[:latex_cache_file])
|
66
|
+
|
69
67
|
begin
|
70
|
-
BlahtexCache.transaction do
|
71
|
-
if BlahtexCache[tex].nil?
|
68
|
+
@@BlahtexCache.transaction do
|
69
|
+
if @@BlahtexCache[tex].nil?
|
72
70
|
tmp_in = Tempfile.new('maruku_blahtex')
|
73
71
|
f = tmp_in.open
|
74
72
|
f.write tex
|
@@ -77,7 +75,7 @@ module MaRuKu; module Out; module HTML
|
|
77
75
|
|
78
76
|
options = "--mathml"
|
79
77
|
cmd = "blahtex #{options} < #{tmp_in.path} > #{tmp_out.path}"
|
80
|
-
|
78
|
+
#$stderr.puts "$ #{cmd}"
|
81
79
|
system cmd
|
82
80
|
tmp_in.delete
|
83
81
|
|
@@ -85,10 +83,10 @@ module MaRuKu; module Out; module HTML
|
|
85
83
|
File.open(tmp_out.path) do |f| result=f.read end
|
86
84
|
puts result
|
87
85
|
|
88
|
-
|
86
|
+
@@BlahtexCache[tex] = result
|
89
87
|
end
|
90
88
|
|
91
|
-
blahtex = BlahtexCache[tex]
|
89
|
+
blahtex = @@BlahtexCache[tex]
|
92
90
|
doc = Document.new(blahtex, {:respect_whitespace =>:all})
|
93
91
|
mathml = doc.root.elements['mathml']
|
94
92
|
if not mathml
|
@@ -337,7 +337,7 @@ module MaRuKu; module In; module Markdown; module BlockLevelParser
|
|
337
337
|
|
338
338
|
# puts "id =_#{id}_; text=_#{text}_ indent=#{indentation}"
|
339
339
|
|
340
|
-
break_list = [:footnote_text]
|
340
|
+
break_list = [:footnote_text, :ref_definition, :definition, :abbreviation]
|
341
341
|
item_type = :footnote_text
|
342
342
|
lines, want_my_paragraph =
|
343
343
|
read_indented_content(src,indentation, break_list, item_type)
|
@@ -471,9 +471,10 @@ module MaRuKu; module In; module Markdown; module BlockLevelParser
|
|
471
471
|
def read_ref_definition(src, out)
|
472
472
|
line = src.shift_line
|
473
473
|
|
474
|
+
|
474
475
|
# if link is incomplete, shift next line
|
475
|
-
if src.cur_line && (src.cur_line.md_type
|
476
|
-
([1,2,3].include? number_of_leading_spaces(src.cur_line) )
|
476
|
+
if src.cur_line && !([:footnote_text, :ref_definition, :definition, :abbreviation].include? src.cur_line.md_type) &&
|
477
|
+
([1,2,3].include? number_of_leading_spaces(src.cur_line) )
|
477
478
|
line += " "+ src.shift_line
|
478
479
|
end
|
479
480
|
|
@@ -647,14 +647,19 @@ module MaRuKu; module In; module Markdown; module SpanLevelParser
|
|
647
647
|
con.push_element md_im_image(alt_text, url, title)
|
648
648
|
when ?[ # link ref
|
649
649
|
ref_id = read_ref_id(src,con)
|
650
|
+
if not ref_id # TODO: check around
|
651
|
+
error('Reference not closed.', src, con)
|
652
|
+
ref_id = ""
|
653
|
+
end
|
650
654
|
if ref_id.size == 0
|
651
|
-
ref_id = alt_text.to_s
|
652
|
-
else
|
653
|
-
ref_id = ref_id.downcase
|
655
|
+
ref_id = alt_text.to_s
|
654
656
|
end
|
657
|
+
|
658
|
+
ref_id = sanitize_ref_id(ref_id)
|
659
|
+
|
655
660
|
con.push_element md_image(alt_text, ref_id)
|
656
661
|
else # no stuff
|
657
|
-
ref_id = alt_text.to_s
|
662
|
+
ref_id = sanitize_ref_id(alt_text.to_s)
|
658
663
|
con.push_element md_image(alt_text, ref_id)
|
659
664
|
end
|
660
665
|
end # read link
|
@@ -94,6 +94,7 @@ module MaRuKu; module Strings
|
|
94
94
|
# *[HTML]: Hyper Text Markup Language
|
95
95
|
Abbreviation = %r{
|
96
96
|
^ # begin of line
|
97
|
+
[ ]{0,3} # up to 3 spaces
|
97
98
|
\* # one asterisk
|
98
99
|
\[ # opening bracket
|
99
100
|
([^\]]+) # any non-closing bracket: id = $1
|
@@ -106,7 +107,9 @@ module MaRuKu; module Strings
|
|
106
107
|
}x
|
107
108
|
|
108
109
|
FootnoteText = %r{
|
109
|
-
|
110
|
+
^ # begin of line
|
111
|
+
[ ]{0,3} # up to 3 spaces
|
112
|
+
\[(\^.+)\]: # id = $1 (including '^')
|
110
113
|
\s*(\S.*)?$ # text = $2 (not obb.)
|
111
114
|
}x
|
112
115
|
|
@@ -115,7 +118,7 @@ module MaRuKu; module Strings
|
|
115
118
|
LinkRegex = %r{
|
116
119
|
^[ ]{0,3}\[([^\[\]]+)\]: # id = $1
|
117
120
|
[ ]*
|
118
|
-
<?(
|
121
|
+
<?([^>\s]+)>? # url = $2
|
119
122
|
[ ]*
|
120
123
|
(?:# Titles are delimited by "quotes" or (parens).
|
121
124
|
["(']
|
@@ -312,7 +312,8 @@ Example:
|
|
312
312
|
li.insert_after(li.children.last, a)
|
313
313
|
ol << li
|
314
314
|
else
|
315
|
-
maruku_error"Could not find footnote '#{fid}'"
|
315
|
+
maruku_error "Could not find footnote id '#{fid}' among ["+
|
316
|
+
self.footnotes.keys.map{|s|"'"+s+"'"}.join(', ')+"]."
|
316
317
|
end
|
317
318
|
end
|
318
319
|
div << ol
|
@@ -827,10 +828,21 @@ If true, raw HTML is discarded from the output.
|
|
827
828
|
# save the order of used footnotes
|
828
829
|
order = @doc.footnotes_order
|
829
830
|
|
831
|
+
if order.include? id
|
832
|
+
# footnote has already been used
|
833
|
+
return []
|
834
|
+
end
|
835
|
+
|
836
|
+
if not @doc.footnotes[id]
|
837
|
+
return []
|
838
|
+
end
|
839
|
+
|
830
840
|
# take next number
|
831
841
|
order << id
|
832
|
-
num = order.size;
|
833
842
|
|
843
|
+
#num = order.size;
|
844
|
+
num = order.index(id) + 1
|
845
|
+
|
834
846
|
sup = Element.new 'sup'
|
835
847
|
sup.attributes['id'] = "#{get_setting(:doc_prefix)}fnref:#{num}"
|
836
848
|
a = Element.new 'a'
|