maruku 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. data/bin/{maruku0.3 → marudown} +6 -14
  2. data/bin/maruku +1 -1
  3. data/bin/marutest +37 -9
  4. data/docs/TOFIX.html +22 -0
  5. data/docs/TOFIX.md +3 -0
  6. data/docs/changelog-0.2.13.html +30 -0
  7. data/docs/changelog-0.2.13.md +6 -0
  8. data/docs/changelog-0.3.html +19 -5
  9. data/docs/faq.html +51 -40
  10. data/docs/faq.md +3 -3
  11. data/docs/hidden_o_n_squared.md +10 -0
  12. data/docs/index.html +84 -396
  13. data/docs/markdown_syntax.html +139 -330
  14. data/docs/markdown_syntax.md +80 -93
  15. data/docs/maruku.html +84 -396
  16. data/docs/maruku.md +88 -158
  17. data/docs/proposal.html +13 -106
  18. data/docs/proposal.md +3 -3
  19. data/docs/todo.html +38 -28
  20. data/lib/maruku.rb +77 -11
  21. data/lib/maruku/attributes.rb +186 -0
  22. data/lib/maruku/defaults.rb +40 -0
  23. data/lib/maruku/errors_management.rb +55 -39
  24. data/lib/maruku/helpers.rb +156 -72
  25. data/lib/maruku/input/charsource.rb +319 -0
  26. data/lib/maruku/{html_helper.rb → input/html_helper.rb} +30 -9
  27. data/lib/maruku/input/linesource.rb +111 -0
  28. data/lib/maruku/input/parse_block.rb +562 -0
  29. data/lib/maruku/{parse_doc.rb → input/parse_doc.rb} +60 -28
  30. data/lib/maruku/{parse_span_better.rb → input/parse_span_better.rb} +226 -256
  31. data/lib/maruku/input/type_detection.rb +137 -0
  32. data/lib/maruku/maruku.rb +33 -0
  33. data/lib/maruku/{to_html.rb → output/to_html.rb} +151 -132
  34. data/lib/maruku/{to_latex.rb → output/to_latex.rb} +31 -35
  35. data/lib/maruku/{to_latex_entities.rb → output/to_latex_entities.rb} +25 -3
  36. data/lib/maruku/output/to_latex_strings.rb +64 -0
  37. data/lib/maruku/output/to_markdown.rb +164 -0
  38. data/lib/maruku/{to_s.rb → output/to_s.rb} +6 -0
  39. data/lib/maruku/string_utils.rb +12 -181
  40. data/lib/maruku/structures.rb +91 -67
  41. data/lib/maruku/structures_inspect.rb +78 -0
  42. data/lib/maruku/structures_iterators.rb +24 -2
  43. data/lib/maruku/tests/benchmark.rb +41 -9
  44. data/lib/maruku/tests/new_parser.rb +317 -286
  45. data/lib/maruku/tests/tests.rb +20 -0
  46. data/lib/maruku/toc.rb +64 -64
  47. data/lib/maruku/usage/example1.rb +33 -0
  48. data/lib/maruku/version.rb +8 -2
  49. data/tests/unittest/abbreviations.md +27 -16
  50. data/tests/unittest/attributes/attributes.md +89 -0
  51. data/tests/unittest/attributes/circular.md +51 -0
  52. data/tests/unittest/attributes/default.md +47 -0
  53. data/tests/unittest/blank.md +10 -6
  54. data/tests/unittest/blanks_in_code.md +26 -26
  55. data/tests/unittest/code.md +9 -9
  56. data/tests/unittest/code2.md +12 -13
  57. data/tests/unittest/code3.md +34 -34
  58. data/tests/unittest/easy.md +9 -7
  59. data/tests/unittest/email.md +9 -7
  60. data/tests/unittest/encoding/iso-8859-1.md +41 -4
  61. data/tests/unittest/encoding/utf-8.md +6 -5
  62. data/tests/unittest/entities.md +52 -80
  63. data/tests/unittest/escaping.md +47 -35
  64. data/tests/unittest/extra_dl.md +19 -29
  65. data/tests/unittest/extra_header_id.md +31 -24
  66. data/tests/unittest/extra_table1.md +14 -32
  67. data/tests/unittest/footnotes.md +58 -42
  68. data/tests/unittest/headers.md +11 -11
  69. data/tests/unittest/hrule.md +14 -24
  70. data/tests/unittest/images.md +41 -26
  71. data/tests/unittest/inline_html.md +104 -56
  72. data/tests/unittest/inline_html2.md +38 -0
  73. data/tests/unittest/links.md +74 -33
  74. data/tests/unittest/list1.md +18 -15
  75. data/tests/unittest/list2.md +31 -13
  76. data/tests/unittest/list3.md +29 -28
  77. data/tests/unittest/list4.md +103 -12
  78. data/tests/unittest/lists.md +86 -53
  79. data/tests/unittest/lists6.md +53 -0
  80. data/tests/unittest/lists7.md +31 -0
  81. data/tests/unittest/lists_after_paragraph.md +105 -71
  82. data/tests/unittest/lists_ol.md +149 -73
  83. data/tests/unittest/misc_sw.md +366 -326
  84. data/tests/unittest/notyet/escape.md +10 -10
  85. data/tests/unittest/notyet/header_after_par.md +20 -14
  86. data/tests/unittest/notyet/ticks.md +8 -35
  87. data/tests/unittest/notyet/triggering.md +72 -45
  88. data/tests/unittest/olist.md +78 -0
  89. data/tests/unittest/one.md +5 -3
  90. data/tests/unittest/paragraph.md +5 -3
  91. data/tests/unittest/paragraph_rules/dont_merge_ref.md +15 -9
  92. data/tests/unittest/paragraph_rules/tab_is_blank.md +9 -5
  93. data/tests/unittest/paragraphs.md +21 -26
  94. data/tests/unittest/recover/recover_links.md +6 -5
  95. data/tests/unittest/references/long_example.md +39 -30
  96. data/tests/unittest/references/spaces_and_numbers.md +2 -2
  97. data/tests/unittest/syntax_hl.md +33 -31
  98. data/tests/unittest/test.md +4 -6
  99. data/tests/unittest/wrapping.md +43 -26
  100. metadata +160 -139
  101. data/docs/markdown_extra2.html +0 -87
  102. data/docs/markdown_extra2.md +0 -83
  103. data/docs/markdown_syntax_2.html +0 -152
  104. data/lib/maruku/parse_block.rb +0 -564
  105. data/lib/maruku/parse_span.rb +0 -451
  106. data/lib/maruku/to_latex_strings.rb +0 -59
  107. data/lib/maruku/to_markdown.rb +0 -110
  108. 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
- class Maruku
22
- def initialize(s=nil, meta={})
23
- @node_type = :document
24
- @doc = self
22
+ require 'iconv'
25
23
 
26
- @refs = {}
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
- @meta.merge! meta2
32
+ self.attributes.merge! meta2
43
33
 
44
- enc = @meta[:encoding]
45
- @meta.delete :encoding
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
- lines = Maruku.split_lines(data)
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.meta[:title] and toc.header_element
56
+ if not self.attributes[:title] and toc.header_element
68
57
  title = toc.header_element.to_s
69
- self.meta[:title] = title
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
- @abbreviations.each do |abbrev, title|
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 = create_md_element(:abbreviation)
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 = create_md_element(:dummy,
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
- class Maruku
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 create_md_element(:linebreak)
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 ??; read_server_directive
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
- # puts "This is HTML: #{src.cur_chars(20)}"
111
+ #puts "This is HTML: #{src.cur_chars(20)}"
89
112
  read_inline_html(src, con)
90
113
  else
91
- # puts "This is NOT HTML: #{src.cur_chars(20)}"
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(/&([\w\d]+);/)
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
- error "Opening * as last char", src, con
124
- tell_user "Threating as literal"
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
- error "Opening _ as last char", src, con
141
- tell_user "Threating as literal"
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
- error ("Unclosed span (waiting for %s"+
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
- def read_simple(src, escaped, exit_on_chars)
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 #{exit_on_chars.inspect})"+
339
+ s= "String finished while reading (break on "+
340
+ "#{exit_on_chars.map{|x|""<<x}.inspect})"+
235
341
  " already read: #{text.inspect}"
236
- error s, src
237
- tell_user "I boldly continue"
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
- tell_user "I will try to continue after bad HTML."
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
- # ignore space
339
- if num_ticks > 1 && src.cur_char == SPACE
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
- code = ''
348
- while true
349
- if not src.cur_char
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: ![a](url "ti"tle")
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
- error 'Unclosed link',src,con
414
- tell_user "No closing ): I will not create"+
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
- tell_user "I will not create the link for #{children.inspect}"
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
- error 'Must quote title',src,con if not title
556
+ if not title
557
+ maruku_error 'Must quote title',src,con
558
+ else
559
+ # Tries to read a title with quotes: ![a](url "ti"tle")
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
- include MarukuStrings
588
+ class SpanContext
589
+ include MaRuKu::Strings
479
590
 
480
- # Read elements
481
- attr_accessor :elements
482
- attr_accessor :cur_string
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
- def push_element(e)
490
- raise "Only MDElement and String, please. You pushed #{e.class}: #{e.inspect} " if
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
- def describe
528
- lines = @elements.map{|x| x.inspect}.join("\n")
529
- s = "Elements read in span: \n" +
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
- if @cur_string.size > 0
533
- s += "Current string: \n #{@cur_string.inspect}\n"
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
- # Return the next n chars as a String.
554
- def cur_chars(n); @buffer[@buffer_index,n] end
555
-
556
- # Return the char after current char as a FixNum (or nil).
557
- def next_char; @buffer[@buffer_index+1] end
558
-
559
- def shift_char
560
- c = @buffer[@buffer_index]
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
- m
602
- end
603
-
604
- def consume_whitespace
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
- end
615
-
616
- def read_text_chars(out)
617
- s = @buffer.size; c=nil
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
- def describe
626
-
627
- len = 75
628
- num_before = [len/2, @buffer_index].min
629
- num_after = [len/2, @buffer.size-@buffer_index].min
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
- pre_s = @buffer_index-index_start
654
- pre_s = [pre_s, 0].max
655
- pre_s2 = [len-pre_s,0].max
656
- # puts "pre_S = #{pre_s}"
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
- # "CharSource: At character #{@buffer_index} of block "+
670
- # " beginning with:\n #{@buffer[0,50].inspect} ...\n"+
671
- # " before: \n ... #{cur_chars(50).inspect} ... "
672
- end
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
- def some
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