maruku 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/{maruku0.3 → marudown} +6 -14
- data/bin/maruku +1 -1
- data/bin/marutest +37 -9
- data/docs/TOFIX.html +22 -0
- data/docs/TOFIX.md +3 -0
- data/docs/changelog-0.2.13.html +30 -0
- data/docs/changelog-0.2.13.md +6 -0
- data/docs/changelog-0.3.html +19 -5
- data/docs/faq.html +51 -40
- data/docs/faq.md +3 -3
- data/docs/hidden_o_n_squared.md +10 -0
- data/docs/index.html +84 -396
- data/docs/markdown_syntax.html +139 -330
- data/docs/markdown_syntax.md +80 -93
- data/docs/maruku.html +84 -396
- data/docs/maruku.md +88 -158
- data/docs/proposal.html +13 -106
- data/docs/proposal.md +3 -3
- data/docs/todo.html +38 -28
- data/lib/maruku.rb +77 -11
- data/lib/maruku/attributes.rb +186 -0
- data/lib/maruku/defaults.rb +40 -0
- data/lib/maruku/errors_management.rb +55 -39
- data/lib/maruku/helpers.rb +156 -72
- data/lib/maruku/input/charsource.rb +319 -0
- data/lib/maruku/{html_helper.rb → input/html_helper.rb} +30 -9
- data/lib/maruku/input/linesource.rb +111 -0
- data/lib/maruku/input/parse_block.rb +562 -0
- data/lib/maruku/{parse_doc.rb → input/parse_doc.rb} +60 -28
- data/lib/maruku/{parse_span_better.rb → input/parse_span_better.rb} +226 -256
- data/lib/maruku/input/type_detection.rb +137 -0
- data/lib/maruku/maruku.rb +33 -0
- data/lib/maruku/{to_html.rb → output/to_html.rb} +151 -132
- data/lib/maruku/{to_latex.rb → output/to_latex.rb} +31 -35
- data/lib/maruku/{to_latex_entities.rb → output/to_latex_entities.rb} +25 -3
- data/lib/maruku/output/to_latex_strings.rb +64 -0
- data/lib/maruku/output/to_markdown.rb +164 -0
- data/lib/maruku/{to_s.rb → output/to_s.rb} +6 -0
- data/lib/maruku/string_utils.rb +12 -181
- data/lib/maruku/structures.rb +91 -67
- data/lib/maruku/structures_inspect.rb +78 -0
- data/lib/maruku/structures_iterators.rb +24 -2
- data/lib/maruku/tests/benchmark.rb +41 -9
- data/lib/maruku/tests/new_parser.rb +317 -286
- data/lib/maruku/tests/tests.rb +20 -0
- data/lib/maruku/toc.rb +64 -64
- data/lib/maruku/usage/example1.rb +33 -0
- data/lib/maruku/version.rb +8 -2
- data/tests/unittest/abbreviations.md +27 -16
- data/tests/unittest/attributes/attributes.md +89 -0
- data/tests/unittest/attributes/circular.md +51 -0
- data/tests/unittest/attributes/default.md +47 -0
- data/tests/unittest/blank.md +10 -6
- data/tests/unittest/blanks_in_code.md +26 -26
- data/tests/unittest/code.md +9 -9
- data/tests/unittest/code2.md +12 -13
- data/tests/unittest/code3.md +34 -34
- data/tests/unittest/easy.md +9 -7
- data/tests/unittest/email.md +9 -7
- data/tests/unittest/encoding/iso-8859-1.md +41 -4
- data/tests/unittest/encoding/utf-8.md +6 -5
- data/tests/unittest/entities.md +52 -80
- data/tests/unittest/escaping.md +47 -35
- data/tests/unittest/extra_dl.md +19 -29
- data/tests/unittest/extra_header_id.md +31 -24
- data/tests/unittest/extra_table1.md +14 -32
- data/tests/unittest/footnotes.md +58 -42
- data/tests/unittest/headers.md +11 -11
- data/tests/unittest/hrule.md +14 -24
- data/tests/unittest/images.md +41 -26
- data/tests/unittest/inline_html.md +104 -56
- data/tests/unittest/inline_html2.md +38 -0
- data/tests/unittest/links.md +74 -33
- data/tests/unittest/list1.md +18 -15
- data/tests/unittest/list2.md +31 -13
- data/tests/unittest/list3.md +29 -28
- data/tests/unittest/list4.md +103 -12
- data/tests/unittest/lists.md +86 -53
- data/tests/unittest/lists6.md +53 -0
- data/tests/unittest/lists7.md +31 -0
- data/tests/unittest/lists_after_paragraph.md +105 -71
- data/tests/unittest/lists_ol.md +149 -73
- data/tests/unittest/misc_sw.md +366 -326
- data/tests/unittest/notyet/escape.md +10 -10
- data/tests/unittest/notyet/header_after_par.md +20 -14
- data/tests/unittest/notyet/ticks.md +8 -35
- data/tests/unittest/notyet/triggering.md +72 -45
- data/tests/unittest/olist.md +78 -0
- data/tests/unittest/one.md +5 -3
- data/tests/unittest/paragraph.md +5 -3
- data/tests/unittest/paragraph_rules/dont_merge_ref.md +15 -9
- data/tests/unittest/paragraph_rules/tab_is_blank.md +9 -5
- data/tests/unittest/paragraphs.md +21 -26
- data/tests/unittest/recover/recover_links.md +6 -5
- data/tests/unittest/references/long_example.md +39 -30
- data/tests/unittest/references/spaces_and_numbers.md +2 -2
- data/tests/unittest/syntax_hl.md +33 -31
- data/tests/unittest/test.md +4 -6
- data/tests/unittest/wrapping.md +43 -26
- metadata +160 -139
- data/docs/markdown_extra2.html +0 -87
- data/docs/markdown_extra2.md +0 -83
- data/docs/markdown_syntax_2.html +0 -152
- data/lib/maruku/parse_block.rb +0 -564
- data/lib/maruku/parse_span.rb +0 -451
- data/lib/maruku/to_latex_strings.rb +0 -59
- data/lib/maruku/to_markdown.rb +0 -110
- data/lib/test.rb +0 -29
@@ -1,3 +1,4 @@
|
|
1
|
+
#--
|
1
2
|
# Copyright (C) 2006 Andrea Censi <andrea (at) rubyforge.org>
|
2
3
|
#
|
3
4
|
# This file is part of Maruku.
|
@@ -15,34 +16,23 @@
|
|
15
16
|
# You should have received a copy of the GNU General Public License
|
16
17
|
# along with Maruku; if not, write to the Free Software
|
17
18
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
19
|
+
#++
|
18
20
|
|
19
|
-
require 'iconv'
|
20
21
|
|
21
|
-
|
22
|
-
def initialize(s=nil, meta={})
|
23
|
-
@node_type = :document
|
24
|
-
@doc = self
|
22
|
+
require 'iconv'
|
25
23
|
|
26
|
-
|
27
|
-
@footnotes = {}
|
28
|
-
@abbreviations = {}
|
29
|
-
@meta = meta
|
30
|
-
|
31
|
-
parse_doc(s) if s
|
32
|
-
end
|
24
|
+
module MaRuKu; module In; module Markdown; module BlockLevelParser
|
33
25
|
|
34
26
|
def parse_doc(s)
|
35
|
-
# setup initial stack
|
36
|
-
@stack = []
|
37
27
|
|
38
28
|
meta2 = parse_email_headers(s)
|
39
29
|
data = meta2[:data]
|
40
30
|
meta2.delete :data
|
41
31
|
|
42
|
-
|
32
|
+
self.attributes.merge! meta2
|
43
33
|
|
44
|
-
enc =
|
45
|
-
|
34
|
+
enc = self.attributes[:encoding]
|
35
|
+
self.attributes.delete :encoding
|
46
36
|
if enc && enc.downcase != 'utf-8'
|
47
37
|
# puts "Converting from #{enc} to UTF-8."
|
48
38
|
converted = Iconv.new('utf-8', enc).iconv(data)
|
@@ -53,8 +43,7 @@ class Maruku
|
|
53
43
|
data = converted
|
54
44
|
end
|
55
45
|
|
56
|
-
|
57
|
-
@children = parse_lines_as_markdown(lines)
|
46
|
+
@children = parse_text_as_markdown(data)
|
58
47
|
|
59
48
|
if true #markdown_extra?
|
60
49
|
self.search_abbreviations
|
@@ -64,26 +53,70 @@ class Maruku
|
|
64
53
|
toc = create_toc
|
65
54
|
|
66
55
|
# use title if not set
|
67
|
-
if not self.
|
56
|
+
if not self.attributes[:title] and toc.header_element
|
68
57
|
title = toc.header_element.to_s
|
69
|
-
self.
|
58
|
+
self.attributes[:title] = title
|
70
59
|
# puts "Set document title to #{title}"
|
71
60
|
end
|
72
61
|
|
73
62
|
# save for later use
|
74
63
|
self.toc = toc
|
75
64
|
|
65
|
+
# Now do the attributes magic
|
66
|
+
each_element do |e|
|
67
|
+
# default attribute list
|
68
|
+
if default = self.ald[e.node_type.to_s]
|
69
|
+
expand_attribute_list(default, e.attributes)
|
70
|
+
end
|
71
|
+
expand_attribute_list(e.al, e.attributes)
|
72
|
+
# puts "#{e.node_type}: #{e.attributes.inspect}"
|
73
|
+
end
|
74
|
+
|
76
75
|
# puts self.inspect
|
77
76
|
end
|
77
|
+
|
78
|
+
# Expands an attribute list in an Hash
|
79
|
+
def expand_attribute_list(al, result)
|
80
|
+
al.each do |k, v|
|
81
|
+
case k
|
82
|
+
when :class
|
83
|
+
if not result[:class]
|
84
|
+
result[:class] = v
|
85
|
+
else
|
86
|
+
result[:class] += " " + v
|
87
|
+
end
|
88
|
+
when :id; result[:id] = v
|
89
|
+
when :ref;
|
90
|
+
if self.ald[v]
|
91
|
+
already = (result[:expanded_references] ||= [])
|
92
|
+
if not already.include?(v)
|
93
|
+
already.push v
|
94
|
+
expand_attribute_list(self.ald[v], result)
|
95
|
+
else
|
96
|
+
maruku_error "Circular reference: #{v} already seen\n"+
|
97
|
+
already.inspect
|
98
|
+
end
|
99
|
+
else
|
100
|
+
if not result[:unresolved_references]
|
101
|
+
result[:unresolved_references] = v
|
102
|
+
else
|
103
|
+
result[:unresolved_references] << " #{v}"
|
104
|
+
end
|
105
|
+
|
106
|
+
result[v.to_sym] = true
|
107
|
+
end
|
108
|
+
else
|
109
|
+
result[k.to_sym]=v
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
78
113
|
|
79
114
|
def search_abbreviations
|
80
|
-
|
115
|
+
self.abbreviations.each do |abbrev, title|
|
81
116
|
reg = Regexp.new(Regexp.escape(abbrev))
|
82
117
|
self.replace_each_string do |s|
|
83
118
|
if m = reg.match(s)
|
84
|
-
e =
|
85
|
-
e.children = [abbrev.dup]
|
86
|
-
e.meta[:title] = title.dup if title
|
119
|
+
e = md_abbr(abbrev.dup, title ? title.dup : nil)
|
87
120
|
[m.pre_match, e, m.post_match]
|
88
121
|
else
|
89
122
|
s
|
@@ -111,7 +144,7 @@ class Maruku
|
|
111
144
|
e.texts.each do |original_text|
|
112
145
|
# puts "parse_blocks = #{parse_blocks} found = #{original_text} "
|
113
146
|
s = original_text.to_s.strip # XXX
|
114
|
-
el =
|
147
|
+
el = md_el(:dummy,
|
115
148
|
parse_blocks ? parse_text_as_markdown(s) :
|
116
149
|
parse_lines_as_span([s]) )
|
117
150
|
el.children_to_html.each do |x|
|
@@ -125,5 +158,4 @@ class Maruku
|
|
125
158
|
end
|
126
159
|
end
|
127
160
|
|
128
|
-
|
129
|
-
end
|
161
|
+
end end end end
|
@@ -1,7 +1,28 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (C) 2006 Andrea Censi <andrea (at) rubyforge.org>
|
3
|
+
#
|
4
|
+
# This file is part of Maruku.
|
5
|
+
#
|
6
|
+
# Maruku is free software; you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation; either version 2 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# Maruku is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with Maruku; if not, write to the Free Software
|
18
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
19
|
+
#++
|
20
|
+
|
21
|
+
|
1
22
|
require 'set'
|
2
23
|
|
3
|
-
|
4
|
-
include Helpers
|
24
|
+
module MaRuKu; module In; module Markdown; module SpanLevelParser
|
25
|
+
include MaRuKu::Helpers
|
5
26
|
|
6
27
|
EscapedCharInText =
|
7
28
|
Set.new [?\\,?`,?*,?_,?{,?},?[,?],?(,?),?#,?.,?!,?|,?:,?+,?-,?>]
|
@@ -36,8 +57,9 @@ class Maruku
|
|
36
57
|
while true
|
37
58
|
c = src.cur_char
|
38
59
|
|
60
|
+
# This is only an optimization which cuts 50% of the time used.
|
61
|
+
# (but you can't use a-zA-z in exit_on_chars)
|
39
62
|
if c && ((c>=?a && c<=?z) || ((c>=?A && c<=?Z)))
|
40
|
-
# src.read_text_chars con.cur_string
|
41
63
|
con.cur_string << src.shift_char
|
42
64
|
next
|
43
65
|
end
|
@@ -49,7 +71,7 @@ class Maruku
|
|
49
71
|
when ?\ # it's space (32)
|
50
72
|
if src.cur_chars_are " \n"
|
51
73
|
src.ignore_chars(3)
|
52
|
-
con.push_element
|
74
|
+
con.push_element md_br()
|
53
75
|
next
|
54
76
|
else
|
55
77
|
src.ignore_char
|
@@ -75,20 +97,21 @@ class Maruku
|
|
75
97
|
else
|
76
98
|
con.push_char src.shift_char
|
77
99
|
end
|
78
|
-
when
|
100
|
+
when ??
|
101
|
+
read_server_directive(src, con)
|
79
102
|
when ?\ , ?\t
|
80
103
|
con.push_char src.shift_char
|
81
|
-
else
|
104
|
+
else
|
82
105
|
if src.next_matches(/<mailto:/) or
|
83
106
|
src.next_matches(/<[\w\.]+\@/)
|
84
107
|
read_email_el(src, con)
|
85
108
|
elsif src.next_matches(/<\w+:/)
|
86
109
|
read_url_el(src, con)
|
87
110
|
elsif src.next_matches(/<\w/)
|
88
|
-
#
|
111
|
+
#puts "This is HTML: #{src.cur_chars(20)}"
|
89
112
|
read_inline_html(src, con)
|
90
113
|
else
|
91
|
-
#
|
114
|
+
#puts "This is NOT HTML: #{src.cur_chars(20)}"
|
92
115
|
con.push_char src.shift_char
|
93
116
|
end
|
94
117
|
end
|
@@ -113,15 +136,15 @@ class Maruku
|
|
113
136
|
con.push_char src.shift_char
|
114
137
|
end
|
115
138
|
when ?&
|
116
|
-
if m = src.read_regexp(
|
139
|
+
if m = src.read_regexp(/\&([\w\d]+);/)
|
117
140
|
con.push_element md_entity(m[1])
|
118
141
|
else
|
119
142
|
con.push_char src.shift_char
|
120
143
|
end
|
121
144
|
when ?*
|
122
145
|
if not src.next_char
|
123
|
-
|
124
|
-
|
146
|
+
maruku_error "Opening * as last char.", src, con
|
147
|
+
maruku_recover "Threating as literal"
|
125
148
|
con.push_char src.shift_char
|
126
149
|
else
|
127
150
|
follows = src.cur_chars(4)
|
@@ -137,8 +160,8 @@ class Maruku
|
|
137
160
|
end
|
138
161
|
when ?_
|
139
162
|
if not src.next_char
|
140
|
-
|
141
|
-
|
163
|
+
maruku_error "Opening _ as last char", src, con
|
164
|
+
maruku_recover "Threating as literal", src, con
|
142
165
|
con.push_char src.shift_char
|
143
166
|
else
|
144
167
|
follows = src.cur_chars(4)
|
@@ -152,21 +175,84 @@ class Maruku
|
|
152
175
|
con.push_char src.shift_char
|
153
176
|
end
|
154
177
|
end
|
178
|
+
when ?{ # inline attribute list
|
179
|
+
if new_meta_data?
|
180
|
+
src.ignore_char # opening {
|
181
|
+
ial = md_ial(al=read_attribute_list(src, con, [?}]))
|
182
|
+
src.ignore_char # closing }
|
183
|
+
|
184
|
+
con.push_element ial
|
185
|
+
else # normal text
|
186
|
+
con.push_char src.shift_char
|
187
|
+
end
|
155
188
|
when nil
|
156
|
-
|
189
|
+
maruku_error ("Unclosed span (waiting for %s"+
|
157
190
|
"#{exit_on_strings.inspect})") % [
|
158
191
|
exit_on_chars ? "#{exit_on_chars.inspect} or" : ""],
|
159
192
|
src,con
|
160
193
|
|
161
|
-
tell_user "I will boldly go ahead."
|
162
194
|
break
|
163
195
|
else # normal text
|
164
196
|
con.push_char src.shift_char
|
165
197
|
end # end case
|
166
198
|
end # end while true
|
167
199
|
con.push_string_if_present
|
200
|
+
|
201
|
+
# Now we handle the IAL stuff
|
202
|
+
# We need a helper
|
203
|
+
def is_ial(e); e.kind_of? MDElement and e.node_type == :ial end
|
204
|
+
# A IAL at the beginning is strange and we ignore it
|
205
|
+
if false && is_ial(e=con.elements[0])
|
206
|
+
"Attribute list at the beginning of span {#{e.to_md}}"
|
207
|
+
tell_user "Ignoring {#{e.to_md}}"
|
208
|
+
con.elements.shift
|
209
|
+
end
|
210
|
+
# Apply each IAL to the element before
|
211
|
+
con.elements.each_with_index do |e, i| if is_ial(e) && i>= 1 then
|
212
|
+
before = con.elements[i-1]
|
213
|
+
if before.kind_of? MDElement
|
214
|
+
#puts "Assigning #{e.ial} to #{before}"
|
215
|
+
before.al = e.ial
|
216
|
+
else
|
217
|
+
maruku_error "This IAL: {#{e.ial.to_md}} seems to"+
|
218
|
+
" refer to a string:\n"+
|
219
|
+
before.inspect, src, con
|
220
|
+
maruku_recover "Ignoring IAL: {#{e.ial.to_md}}", src, con
|
221
|
+
end
|
222
|
+
end end
|
223
|
+
|
224
|
+
# Remove all IAL
|
225
|
+
# con.elements.delete_if { |e| is_ial(e) }
|
226
|
+
|
227
|
+
# Remove leading space
|
228
|
+
if (s = con.elements.first).kind_of? String
|
229
|
+
if s[0] == ?\ then con.elements[0] = s[1, s.size-1] end
|
230
|
+
con.elements.shift if s.size == 0
|
231
|
+
end
|
232
|
+
|
233
|
+
# Remove final spaces
|
234
|
+
if (s = con.elements.last).kind_of? String
|
235
|
+
s.chop! if s[-1] == ?\
|
236
|
+
con.elements.pop if s.size == 0
|
237
|
+
end
|
238
|
+
|
168
239
|
con.elements
|
169
240
|
end
|
241
|
+
|
242
|
+
def read_server_directive(src, con)
|
243
|
+
delim = "?>"
|
244
|
+
|
245
|
+
src.ignore_chars delim.size
|
246
|
+
|
247
|
+
code =
|
248
|
+
read_simple(src, escaped=[], break_on_chars=[],
|
249
|
+
break_on_strings=[delim])
|
250
|
+
|
251
|
+
src.ignore_chars delim.size
|
252
|
+
|
253
|
+
code = (code || "").strip
|
254
|
+
con.push_element md_server(code)
|
255
|
+
end
|
170
256
|
|
171
257
|
def read_url_el(src,con)
|
172
258
|
src.ignore_char # leading <
|
@@ -191,6 +277,9 @@ class Maruku
|
|
191
277
|
end
|
192
278
|
|
193
279
|
url = read_simple(src, [], break_on)
|
280
|
+
if not url # empty url
|
281
|
+
url = ""
|
282
|
+
end
|
194
283
|
|
195
284
|
if url[0] == ?< && url[-1] == ?>
|
196
285
|
url = url[1, url.size-2]
|
@@ -203,9 +292,19 @@ class Maruku
|
|
203
292
|
url
|
204
293
|
end
|
205
294
|
|
295
|
+
|
296
|
+
def read_quoted_or_unquoted(src, con, escaped, exit_on_chars)
|
297
|
+
case src.cur_char
|
298
|
+
when ?', ?"
|
299
|
+
read_quoted(src, con)
|
300
|
+
else
|
301
|
+
read_simple(src, escaped, exit_on_chars)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
206
305
|
# Tries to read a quoted value. If stream does not
|
207
306
|
# start with ' or ", returns nil.
|
208
|
-
def read_quoted(src,con)
|
307
|
+
def read_quoted(src, con)
|
209
308
|
case src.cur_char
|
210
309
|
when ?', ?"
|
211
310
|
quote_char = src.shift_char # opening quote
|
@@ -219,8 +318,10 @@ class Maruku
|
|
219
318
|
end
|
220
319
|
|
221
320
|
# Reads a simple string (no formatting) until one of break_on_chars,
|
222
|
-
# while escaping the escaped
|
223
|
-
|
321
|
+
# while escaping the escaped.
|
322
|
+
# If the string is empty, it returns nil.
|
323
|
+
# Raises on error.
|
324
|
+
def read_simple(src, escaped, exit_on_chars, exit_on_strings=nil)
|
224
325
|
text = ""
|
225
326
|
while true
|
226
327
|
# puts "Reading simple #{text.inspect}"
|
@@ -229,12 +330,17 @@ class Maruku
|
|
229
330
|
# puts (" breaking on "<<c)+" contained in "+exit_on_chars.inspect
|
230
331
|
break
|
231
332
|
end
|
333
|
+
|
334
|
+
break if exit_on_strings &&
|
335
|
+
exit_on_strings.any? {|x| src.cur_chars_are x}
|
336
|
+
|
232
337
|
case c
|
233
338
|
when nil
|
234
|
-
s= "String finished while reading (break on
|
339
|
+
s= "String finished while reading (break on "+
|
340
|
+
"#{exit_on_chars.map{|x|""<<x}.inspect})"+
|
235
341
|
" already read: #{text.inspect}"
|
236
|
-
|
237
|
-
|
342
|
+
maruku_error s, src
|
343
|
+
maruku_recover "I boldly continue", src, con
|
238
344
|
break
|
239
345
|
when ?\\
|
240
346
|
d = src.next_char
|
@@ -249,7 +355,7 @@ class Maruku
|
|
249
355
|
end
|
250
356
|
end
|
251
357
|
# puts "Read simple #{text.inspect}"
|
252
|
-
text
|
358
|
+
text.empty? ? nil : text
|
253
359
|
end
|
254
360
|
|
255
361
|
def read_em(src, delim)
|
@@ -321,48 +427,33 @@ class Maruku
|
|
321
427
|
maruku_error "Bad html: \n" +
|
322
428
|
add_tabs(e.inspect+e.backtrace.join("\n"),1,'>'),
|
323
429
|
src,con
|
324
|
-
|
430
|
+
maruku_recover "I will try to continue after bad HTML.", src, con
|
325
431
|
con.push_char src.shift_char
|
326
432
|
end
|
327
433
|
end
|
328
434
|
|
329
435
|
def read_inline_code(src, con)
|
436
|
+
# Count the number of ticks
|
330
437
|
num_ticks = 0
|
331
|
-
|
332
438
|
while src.cur_char == ?`
|
333
439
|
num_ticks += 1
|
334
440
|
src.ignore_char
|
335
441
|
end
|
442
|
+
# We will read until this string
|
443
|
+
end_string = "`"*num_ticks
|
336
444
|
|
445
|
+
code =
|
446
|
+
read_simple(src, escaped=[], break_on_chars=[],
|
447
|
+
break_on_strings=[end_string])
|
337
448
|
|
338
|
-
#
|
339
|
-
|
340
|
-
src.ignore_char
|
341
|
-
end
|
342
|
-
|
343
|
-
# puts "Ticks: #{num_ticks } next: #{src.some} "
|
344
|
-
|
345
|
-
end_string = "`"*num_ticks
|
449
|
+
# puts "Now I expects #{num_ticks} ticks: #{src.cur_chars(10).inspect}"
|
450
|
+
src.ignore_chars num_ticks
|
346
451
|
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
error("Ticks not finished: read #{code.inspect}"+
|
351
|
-
" and waiting for #{end_string.inspect} num=#{num_ticks}",
|
352
|
-
src,con)
|
353
|
-
tell_user "Read invalid code block: #{code.inspect}"
|
354
|
-
break
|
355
|
-
end
|
356
|
-
|
357
|
-
if src.cur_chars(num_ticks) ==end_string # bah
|
358
|
-
# puts "Breaking on #{src.some} (end:#{end_string.inspect})"
|
359
|
-
src.ignore_chars num_ticks
|
360
|
-
break
|
361
|
-
end
|
362
|
-
|
363
|
-
code << src.shift_char
|
452
|
+
# Ignore at most one space
|
453
|
+
if num_ticks > 1 && code[0] == SPACE
|
454
|
+
code = code[1, code.size-1]
|
364
455
|
end
|
365
|
-
|
456
|
+
|
366
457
|
# drop last space
|
367
458
|
if num_ticks > 1 && code[-1] == SPACE
|
368
459
|
code = code[0,code.size-1]
|
@@ -371,17 +462,6 @@ class Maruku
|
|
371
462
|
# puts "Read `` code: #{code.inspect}; after: #{src.cur_chars(10).inspect} "
|
372
463
|
con.push_element md_code(code)
|
373
464
|
end
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
def read_server_directive
|
378
|
-
# match = gimme(/^(.*)\?>/)
|
379
|
-
# if not match
|
380
|
-
# error "Server directive not closed"
|
381
|
-
# end
|
382
|
-
# server = match[1]
|
383
|
-
# con.found_object create_md_element(:server, server)
|
384
|
-
end
|
385
465
|
|
386
466
|
def read_link(src, con)
|
387
467
|
# we read the string and see what happens
|
@@ -405,14 +485,31 @@ class Maruku
|
|
405
485
|
src.consume_whitespace
|
406
486
|
title = nil
|
407
487
|
if src.cur_char != ?) # we have a title
|
488
|
+
quote_char = src.cur_char
|
408
489
|
title = read_quoted(src,con)
|
490
|
+
|
491
|
+
if not title
|
492
|
+
maruku_error 'Must quote title',src,con
|
493
|
+
else
|
494
|
+
# Tries to read a title with quotes: 
|
495
|
+
# this is the most ugly thing in Markdown
|
496
|
+
if not src.next_matches(/\s*\)/)
|
497
|
+
# if there is not a closing par ), then read
|
498
|
+
# the rest and guess it's title with quotes
|
499
|
+
rest = read_simple(src, escaped=[], break_on_chars=[?)],
|
500
|
+
break_on_strings=[])
|
501
|
+
# chop the closing char
|
502
|
+
rest.chop!
|
503
|
+
title << quote_char << rest
|
504
|
+
end
|
505
|
+
end
|
409
506
|
end
|
410
507
|
src.consume_whitespace
|
411
508
|
closing = src.shift_char # closing )
|
412
509
|
if closing != ?)
|
413
|
-
|
414
|
-
|
415
|
-
" the link for #{children.inspect}"
|
510
|
+
maruku_error 'Unclosed link',src,con
|
511
|
+
maruku_recover "No closing ): I will not create"+
|
512
|
+
" the link for #{children.inspect}", src, con
|
416
513
|
con.push_elements children
|
417
514
|
return
|
418
515
|
end
|
@@ -423,7 +520,8 @@ class Maruku
|
|
423
520
|
con.push_element md_link(children, ref_id)
|
424
521
|
else
|
425
522
|
maruku_error "Could not read ref_id", src, con
|
426
|
-
|
523
|
+
maruku_recover "I will not create the link for "+
|
524
|
+
"#{children.inspect}", src, con
|
427
525
|
con.push_elements children
|
428
526
|
return
|
429
527
|
end
|
@@ -453,8 +551,23 @@ class Maruku
|
|
453
551
|
src.consume_whitespace
|
454
552
|
title = nil
|
455
553
|
if src.cur_char != ?) # we have a title
|
554
|
+
quote_char = src.cur_char
|
456
555
|
title = read_quoted(src,con)
|
457
|
-
|
556
|
+
if not title
|
557
|
+
maruku_error 'Must quote title',src,con
|
558
|
+
else
|
559
|
+
# Tries to read a title with quotes: 
|
560
|
+
# this is the most ugly thing in Markdown
|
561
|
+
if not src.next_matches(/\s*\)/)
|
562
|
+
# if there is not a closing par ), then read
|
563
|
+
# the rest and guess it's title with quotes
|
564
|
+
rest = read_simple(src, escaped=[], break_on_chars=[?)],
|
565
|
+
break_on_strings=[])
|
566
|
+
# chop the closing char
|
567
|
+
rest.chop!
|
568
|
+
title << quote_char << rest
|
569
|
+
end
|
570
|
+
end
|
458
571
|
end
|
459
572
|
src.consume_whitespace
|
460
573
|
closing = src.shift_char # closing )
|
@@ -471,211 +584,68 @@ class Maruku
|
|
471
584
|
end
|
472
585
|
end # read link
|
473
586
|
|
474
|
-
end
|
475
|
-
|
476
587
|
|
477
|
-
class SpanContext
|
478
|
-
|
588
|
+
class SpanContext
|
589
|
+
include MaRuKu::Strings
|
479
590
|
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
def initialize
|
485
|
-
@elements = []
|
486
|
-
@cur_string = ""
|
487
|
-
end
|
591
|
+
# Read elements
|
592
|
+
attr_accessor :elements
|
593
|
+
attr_accessor :cur_string
|
488
594
|
|
489
|
-
|
490
|
-
|
491
|
-
not (e.kind_of?(String) or e.kind_of?(MDElement))
|
492
|
-
|
493
|
-
push_string_if_present
|
494
|
-
@elements << e
|
495
|
-
nil
|
496
|
-
end
|
497
|
-
|
498
|
-
def push_elements(a)
|
499
|
-
for e in a
|
500
|
-
if e.kind_of? String
|
501
|
-
e.each_byte do |b| push_char b end
|
502
|
-
else
|
503
|
-
push_element e
|
504
|
-
end
|
505
|
-
end
|
506
|
-
end
|
507
|
-
def push_string_if_present
|
508
|
-
if @cur_string.size > 0
|
509
|
-
@elements << @cur_string
|
595
|
+
def initialize
|
596
|
+
@elements = []
|
510
597
|
@cur_string = ""
|
511
598
|
end
|
512
|
-
nil
|
513
|
-
end
|
514
|
-
|
515
|
-
def push_char(c)
|
516
|
-
@cur_string << c
|
517
|
-
nil
|
518
|
-
end
|
519
|
-
|
520
|
-
# push space into current string if
|
521
|
-
# there isn't one
|
522
|
-
def push_space
|
523
|
-
last = @cur_string[@cur_string.size-1]
|
524
|
-
@cur_string << ?\ if last != ?\
|
525
|
-
end
|
526
599
|
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
add_tabs(lines,1, ' -')+"\n"
|
600
|
+
def push_element(e)
|
601
|
+
raise "Only MDElement and String, please. You pushed #{e.class}: #{e.inspect} " if
|
602
|
+
not (e.kind_of?(String) or e.kind_of?(MDElement))
|
531
603
|
|
532
|
-
|
533
|
-
|
604
|
+
push_string_if_present
|
605
|
+
@elements << e
|
606
|
+
nil
|
534
607
|
end
|
535
|
-
s
|
536
|
-
end
|
537
|
-
|
538
|
-
end
|
539
|
-
|
540
|
-
class CharSource
|
541
|
-
include MarukuStrings
|
542
|
-
|
543
|
-
def initialize(s)
|
544
|
-
@elements = []
|
545
|
-
@cur_string = ""
|
546
|
-
@buffer = s
|
547
|
-
@buffer_index = 0
|
548
|
-
end
|
549
|
-
|
550
|
-
# Return current char as a FixNum (or nil).
|
551
|
-
def cur_char; @buffer[@buffer_index] end
|
552
608
|
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
@buffer_index+=1
|
562
|
-
c
|
563
|
-
end
|
564
|
-
|
565
|
-
def ignore_char
|
566
|
-
@buffer_index+=1
|
567
|
-
end
|
568
|
-
|
569
|
-
def ignore_chars(n)
|
570
|
-
@buffer_index+=n
|
571
|
-
nil
|
572
|
-
end
|
573
|
-
|
574
|
-
def current_remaining_buffer
|
575
|
-
@buffer[@buffer_index, @buffer.size-@buffer_index]
|
576
|
-
end
|
577
|
-
|
578
|
-
def cur_chars_are(string)
|
579
|
-
r2 = /^.{#{@buffer_index}}#{Regexp.escape string}/m
|
580
|
-
@buffer =~ r2
|
581
|
-
end
|
582
|
-
|
583
|
-
def next_matches(r)
|
584
|
-
r2 = /^.{#{@buffer_index}}#{r}/m
|
585
|
-
r2.match @buffer
|
586
|
-
end
|
587
|
-
|
588
|
-
def read_regexp(r)
|
589
|
-
r2 = /^.{#{@buffer_index}}#{r}/m
|
590
|
-
m = r2.match @buffer
|
591
|
-
if m
|
592
|
-
consumed = m.to_s.size - @buffer_index
|
593
|
-
# puts "Consumed #{consumed} chars (entire is #{m.to_s.inspect})"
|
594
|
-
ignore_chars consumed
|
595
|
-
else
|
596
|
-
# puts "Could not read regexp #{r2.inspect} from buffer "+
|
597
|
-
# " index=#{@buffer_index}"
|
598
|
-
# puts "Cur chars = #{cur_chars(20).inspect}"
|
599
|
-
# puts "Matches? = #{cur_chars(20) =~ r}"
|
609
|
+
def push_elements(a)
|
610
|
+
for e in a
|
611
|
+
if e.kind_of? String
|
612
|
+
e.each_byte do |b| push_char b end
|
613
|
+
else
|
614
|
+
push_element e
|
615
|
+
end
|
616
|
+
end
|
600
617
|
end
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
while c = cur_char
|
606
|
-
if (c == 32 || c == ?\t)
|
607
|
-
# puts "ignoring #{c}"
|
608
|
-
ignore_char
|
609
|
-
else
|
610
|
-
# puts "#{c} is not ws: "<<c
|
611
|
-
break
|
618
|
+
def push_string_if_present
|
619
|
+
if @cur_string.size > 0
|
620
|
+
@elements << @cur_string
|
621
|
+
@cur_string = ""
|
612
622
|
end
|
623
|
+
nil
|
613
624
|
end
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
while @buffer_index < s && (c=@buffer[@buffer_index]) &&
|
619
|
-
((c>=?a && c<=?z) || (c>=?A && c<=?Z))
|
620
|
-
out << c
|
621
|
-
@buffer_index += 1
|
625
|
+
|
626
|
+
def push_char(c)
|
627
|
+
@cur_string << c
|
628
|
+
nil
|
622
629
|
end
|
623
|
-
end
|
624
630
|
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
num_before_max = @buffer_index
|
631
|
-
num_after_max = @buffer.size-@buffer_index
|
632
|
-
|
633
|
-
# puts "num #{num_before} #{num_after}"
|
634
|
-
num_before = [num_before_max, len-num_after].min
|
635
|
-
num_after = [num_after_max, len-num_before].min
|
636
|
-
# puts "num #{num_before} #{num_after}"
|
637
|
-
|
638
|
-
index_start = [@buffer_index - num_before, 0].max
|
639
|
-
index_end = [@buffer_index + num_after, @buffer.size].min
|
640
|
-
|
641
|
-
size = index_end- index_start
|
642
|
-
|
643
|
-
# puts "- #{index_start} #{size}"
|
644
|
-
|
645
|
-
str = @buffer[index_start, size]
|
646
|
-
str.gsub!("\n",'N')
|
647
|
-
str.gsub!("\t",'T')
|
648
|
-
|
649
|
-
if index_end == @buffer.size
|
650
|
-
str += "EOF"
|
631
|
+
# push space into current string if
|
632
|
+
# there isn't one
|
633
|
+
def push_space
|
634
|
+
last = @cur_string[@cur_string.size-1]
|
635
|
+
@cur_string << ?\ if last != ?\
|
651
636
|
end
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
pre =" "*(pre_s)
|
658
|
-
|
659
|
-
"-"*len+"\n"+
|
660
|
-
str + "\n" +
|
661
|
-
"-"*pre_s + "|" + "-"*(pre_s2)+"\n"+
|
662
|
-
# pre + "|\n"+
|
663
|
-
pre + "+--- Byte #{@buffer_index}\n"+
|
664
|
-
|
665
|
-
|
666
|
-
"Shown bytes [#{index_start} to #{size}] of #{@buffer.size}:\n"+
|
667
|
-
add_tabs(@buffer,1,">")
|
637
|
+
|
638
|
+
def describe
|
639
|
+
lines = @elements.map{|x| x.inspect}.join("\n")
|
640
|
+
s = "Elements read in span: \n" +
|
641
|
+
add_tabs(lines,1, ' -')+"\n"
|
668
642
|
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
643
|
+
if @cur_string.size > 0
|
644
|
+
s += "Current string: \n #{@cur_string.inspect}\n"
|
645
|
+
end
|
646
|
+
s
|
647
|
+
end
|
648
|
+
end # SpanContext
|
673
649
|
|
674
|
-
|
675
|
-
cur_chars(15).inspect
|
676
|
-
end
|
677
|
-
end
|
678
|
-
|
679
|
-
|
680
|
-
|
650
|
+
end end end end # module MaRuKu; module In; module Markdown; module SpanLevelParser
|
681
651
|
|