omf_web 1.2.3 → 1.2.4
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/lib/irods4r/file.rb +2 -0
- data/lib/irods4r/icommands.rb +5 -0
- data/lib/irods4r.rb +1 -1
- data/lib/omf-web/content/git_repository.rb +3 -1
- data/lib/omf-web/content/irods_repository.rb +1 -1
- data/lib/omf-web/content/repository.rb +1 -0
- data/lib/omf-web/data_source_proxy.rb +14 -0
- data/lib/omf-web/theme/abstract_page.rb +4 -1
- data/lib/omf-web/thin/logging.rb +8 -1
- data/lib/omf-web/version.rb +1 -1
- data/lib/omf-web/widget/data_widget.rb +6 -1
- data/lib/omf-web/widget/text/maruku/helpers.rb +211 -211
- data/lib/omf-web/widget/text/maruku/input/parse_block.rb +498 -499
- data/lib/omf-web/widget/text/maruku/output/to_html.rb +810 -808
- data/lib/omf-web/widget/text/maruku.rb +54 -18
- data/lib/omf-web/widget/text/text_widget.rb +13 -13
- data/share/htdocs/graph/js/abstract_widget.js +1 -1
- data/share/htdocs/js/data_source3.js +36 -8
- data/share/htdocs/js/data_source_repo.js +14 -6
- metadata +2 -2
@@ -21,596 +21,595 @@
|
|
21
21
|
|
22
22
|
module MaRuKu; module In; module Markdown; module BlockLevelParser
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
24
|
+
include Helpers
|
25
|
+
include MaRuKu::Strings
|
26
|
+
include MaRuKu::In::Markdown::SpanLevelParser
|
27
|
+
|
28
|
+
class BlockContext < Array
|
29
|
+
def describe
|
30
|
+
n = 5
|
31
|
+
desc = size > n ? self[-n,n] : self
|
32
|
+
"Last #{n} elements: "+
|
33
|
+
desc.map{|x| "\n -" + x.inspect}.join
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Splits the string and calls parse_lines_as_markdown
|
38
|
+
def parse_text_as_markdown(text)
|
39
|
+
lines = split_lines(text)
|
40
|
+
src = LineSource.new(lines)
|
41
|
+
return parse_blocks(src)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Input is a LineSource
|
45
|
+
def parse_blocks(src)
|
46
|
+
output = BlockContext.new
|
47
|
+
|
48
|
+
# run state machine
|
49
|
+
while src.cur_line
|
50
|
+
|
51
|
+
next if check_block_extensions(src, output, src.cur_line)
|
52
52
|
|
53
53
|
# Prints detected type (useful for debugging)
|
54
|
-
#
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
54
|
+
#puts "PARSE>>>> #{src.cur_line.md_type}|#{src.cur_line}"
|
55
|
+
case src.cur_line.md_type
|
56
|
+
when :empty;
|
57
|
+
output.push :empty
|
58
|
+
src.ignore_line
|
59
|
+
when :ial
|
60
|
+
m = InlineAttributeList.match src.shift_line
|
61
|
+
content = m[1] || ""
|
62
62
|
# puts "Content: #{content.inspect}"
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
def read_header3(src)
|
63
|
+
src2 = CharSource.new(content, src)
|
64
|
+
interpret_extension(src2, output, [nil])
|
65
|
+
when :ald
|
66
|
+
output.push read_ald(src)
|
67
|
+
when :text
|
68
|
+
# paragraph, or table, or definition list
|
69
|
+
read_text_material(src, output)
|
70
|
+
when :header2, :hrule
|
71
|
+
src.shift_line
|
72
|
+
output.push md_hrule()
|
73
|
+
when :header3
|
74
|
+
output.push read_header3(src)
|
75
|
+
when :ulist, :olist
|
76
|
+
list_type = src.cur_line.md_type == :ulist ? :ul : :ol
|
77
|
+
li = read_list_item(src)
|
78
|
+
# append to current list if we have one
|
79
|
+
if output.last.kind_of?(MDElement) &&
|
80
|
+
output.last.node_type == list_type then
|
81
|
+
output.last.children << li
|
82
|
+
else
|
83
|
+
output.push md_el(list_type, [li])
|
84
|
+
end
|
85
|
+
when :quote; output.push read_quote(src)
|
86
|
+
when :code; e = read_code(src); output << e if e
|
87
|
+
when :raw_html; e = read_raw_html(src); output << e if e
|
88
|
+
|
89
|
+
when :footnote_text; output.push read_footnote_text(src)
|
90
|
+
when :ref_definition
|
91
|
+
if src.parent && (src.cur_index == 0)
|
92
|
+
read_text_material(src, output)
|
93
|
+
else
|
94
|
+
read_ref_definition(src, output)
|
95
|
+
end
|
96
|
+
when :abbreviation; output.push read_abbreviation(src)
|
97
|
+
when :xml_instr; read_xml_instruction(src, output)
|
98
|
+
when :metadata;
|
99
|
+
maruku_error "Please use the new meta-data syntax: \n"+
|
100
|
+
" http://maruku.rubyforge.org/proposal.html\n", src
|
101
|
+
src.ignore_line
|
102
|
+
else # warn if we forgot something
|
103
|
+
md_type = src.cur_line.md_type
|
104
|
+
line = src.cur_line
|
105
|
+
maruku_error "Ignoring line '#{line}' type = #{md_type}", src
|
106
|
+
src.shift_line
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
merge_ial(output, src, output)
|
111
|
+
output.delete_if {|x| x.kind_of?(MDElement) &&
|
112
|
+
x.node_type == :ial}
|
113
|
+
|
114
|
+
# get rid of empty line markers
|
115
|
+
output.delete_if {|x| x == :empty}
|
116
|
+
# See for each list if we can omit the paragraphs and use li_span
|
117
|
+
# TODO: do this after
|
118
|
+
output.each do |c|
|
119
|
+
# Remove paragraphs that we can get rid of
|
120
|
+
if [:ul,:ol].include? c.node_type
|
121
|
+
if c.children.all? {|li| !li.want_my_paragraph} then
|
122
|
+
c.children.each do |d|
|
123
|
+
d.node_type = :li_span
|
124
|
+
d.children = d.children[0].children
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
if c.node_type == :definition_list
|
129
|
+
if c.children.all?{|defi| !defi.want_my_paragraph} then
|
130
|
+
c.children.each do |definition|
|
131
|
+
definition.definitions.each do |dd|
|
132
|
+
dd.children = dd.children[0].children
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
output
|
140
|
+
end
|
141
|
+
|
142
|
+
def read_text_material(src, output)
|
143
|
+
if src.cur_line =~ MightBeTableHeader and
|
144
|
+
(src.next_line && src.next_line =~ TableSeparator)
|
145
|
+
output.push read_table(src)
|
146
|
+
elsif [:header1,:header2].include? src.next_line.md_type
|
147
|
+
output.push read_header12(src)
|
148
|
+
elsif eventually_comes_a_def_list(src)
|
149
|
+
definition = read_definition(src)
|
150
|
+
if output.last.kind_of?(MDElement) &&
|
151
|
+
output.last.node_type == :definition_list then
|
152
|
+
output.last.children << definition
|
153
|
+
else
|
154
|
+
output.push md_el(:definition_list, [definition])
|
155
|
+
end
|
156
|
+
else # Start of a paragraph
|
157
|
+
output.push read_paragraph(src)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
def read_ald(src)
|
163
|
+
if (l=src.shift_line) =~ AttributeDefinitionList
|
164
|
+
id = $1; al=$2;
|
165
|
+
al = read_attribute_list(CharSource.new(al,src), context=nil, break_on=[nil])
|
166
|
+
self.ald[id] = al;
|
167
|
+
return md_ald(id, al)
|
168
|
+
else
|
169
|
+
maruku_error "Bug Bug:\n#{l.inspect}"
|
170
|
+
return nil
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# reads a header (with ----- or ========)
|
175
|
+
def read_header12(src)
|
176
|
+
line = src.shift_line.strip
|
177
|
+
al = nil
|
178
|
+
# Check if there is an IAL
|
179
|
+
if new_meta_data? and line =~ /^(.*)\{(.*)\}\s*$/
|
180
|
+
line = $1.strip
|
181
|
+
ial = $2
|
182
|
+
al = read_attribute_list(CharSource.new(ial,src), context=nil, break_on=[nil])
|
183
|
+
end
|
184
|
+
text = parse_lines_as_span [ line ]
|
185
|
+
level = src.cur_line.md_type == :header2 ? 2 : 1;
|
186
|
+
src.shift_line
|
187
|
+
return md_header(level, text, al, src.cur_index)
|
188
|
+
end
|
189
|
+
|
190
|
+
# reads a header like '#### header ####'
|
191
|
+
def read_header3(src)
|
193
192
|
# puts "READ_H3: #{src.inspect}"
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
193
|
+
line = src.shift_line.strip
|
194
|
+
al = nil
|
195
|
+
# Check if there is an IAL
|
196
|
+
if new_meta_data? and line =~ /^(.*)\{(.*)\}\s*$/
|
197
|
+
line = $1.strip
|
198
|
+
ial = $2
|
199
|
+
al = read_attribute_list(CharSource.new(ial,src), context=nil, break_on=[nil])
|
200
|
+
end
|
201
|
+
level = num_leading_hashes(line)
|
202
|
+
text = parse_lines_as_span [strip_hashes(line)]
|
203
|
+
return md_header(level, text, al, src.cur_index)
|
204
|
+
end
|
205
|
+
|
206
|
+
def read_xml_instruction(src, output)
|
207
|
+
m = /^\s*<\?((\w+)\s*)?(.*)$/.match src.shift_line
|
208
|
+
raise "BugBug" if not m
|
209
|
+
target = m[2] || ''
|
210
|
+
code = m[3]
|
211
|
+
until code =~ /\?>/
|
212
|
+
code += "\n"+src.shift_line
|
213
|
+
end
|
214
|
+
if not code =~ (/\?>\s*$/)
|
215
|
+
garbage = (/\?>(.*)$/.match(code))[1]
|
216
|
+
maruku_error "Trailing garbage on last line: #{garbage.inspect}:\n"+
|
217
|
+
add_tabs(code, 1, '|'), src
|
218
|
+
end
|
219
|
+
code.gsub!(/\?>\s*$/, '')
|
220
|
+
|
221
|
+
if target == 'mrk' && MaRuKu::Globals[:unsafe_features]
|
222
|
+
result = safe_execute_code(self, code)
|
223
|
+
if result
|
224
|
+
if result.kind_of? String
|
225
|
+
raise "Not expected"
|
226
|
+
else
|
227
|
+
output.push(*result)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
else
|
231
|
+
output.push md_xml_instr(target, code)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def read_raw_html(src)
|
236
|
+
h = HTMLHelper.new
|
237
|
+
begin
|
238
|
+
h.eat_this(l=src.shift_line)
|
240
239
|
# puts "\nBLOCK:\nhtml -> #{l.inspect}"
|
241
|
-
|
242
|
-
|
240
|
+
while src.cur_line and not h.is_finished?
|
241
|
+
l=src.shift_line
|
243
242
|
# puts "html -> #{l.inspect}"
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
243
|
+
h.eat_this "\n"+l
|
244
|
+
end
|
245
|
+
rescue Exception => e
|
246
|
+
ex = e.inspect + e.backtrace.join("\n")
|
247
|
+
maruku_error "Bad block-level HTML:\n#{add_tabs(ex,1,'|')}\n", src
|
248
|
+
end
|
249
|
+
if not (h.rest =~ /^\s*$/)
|
250
|
+
maruku_error "Could you please format this better?\n"+
|
251
|
+
"I see that #{h.rest.inspect} is left after the raw HTML.", src
|
252
|
+
end
|
253
|
+
raw_html = h.stuff_you_read
|
254
|
+
|
255
|
+
return md_html(raw_html)
|
256
|
+
end
|
257
|
+
|
258
|
+
def read_paragraph(src)
|
259
|
+
lines = [src.shift_line]
|
260
|
+
while src.cur_line
|
261
|
+
# :olist does not break
|
262
|
+
case t = src.cur_line.md_type
|
263
|
+
when :quote,:header3,:empty,:ref_definition,:ial #,:xml_instr,:raw_html
|
264
|
+
break
|
265
|
+
when :olist,:ulist
|
266
|
+
break if src.next_line.md_type == t
|
267
|
+
end
|
268
|
+
break if src.cur_line.strip.size == 0
|
269
|
+
break if [:header1,:header2].include? src.next_line.md_type
|
270
|
+
break if any_matching_block_extension?(src.cur_line)
|
271
|
+
|
272
|
+
lines << src.shift_line
|
273
|
+
end
|
275
274
|
# dbg_describe_ary(lines, 'PAR')
|
276
|
-
|
275
|
+
children = parse_lines_as_span(lines, src)
|
277
276
|
|
278
|
-
|
279
|
-
|
277
|
+
return md_par(children, nil, src.cur_index)
|
278
|
+
end
|
280
279
|
|
281
|
-
|
282
|
-
|
283
|
-
|
280
|
+
# Reads one list item, either ordered or unordered.
|
281
|
+
def read_list_item(src)
|
282
|
+
parent_offset = src.cur_index
|
284
283
|
|
285
|
-
|
286
|
-
|
284
|
+
item_type = src.cur_line.md_type
|
285
|
+
first = src.shift_line
|
287
286
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
287
|
+
indentation, ial = spaces_before_first_char(first)
|
288
|
+
al = read_attribute_list(CharSource.new(ial,src), context=nil, break_on=[nil]) if ial
|
289
|
+
break_list = [:ulist, :olist, :ial]
|
290
|
+
# Ugly things going on inside `read_indented_content`
|
291
|
+
lines, want_my_paragraph =
|
292
|
+
read_indented_content(src,indentation, break_list, item_type)
|
294
293
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
294
|
+
# add first line
|
295
|
+
# Strip first '*', '-', '+' from first line
|
296
|
+
stripped = first[indentation, first.size-1]
|
297
|
+
lines.unshift stripped
|
299
298
|
|
300
|
-
|
299
|
+
# dbg_describe_ary(lines, 'LIST ITEM ')
|
301
300
|
|
302
|
-
|
303
|
-
|
304
|
-
|
301
|
+
src2 = LineSource.new(lines, src, parent_offset)
|
302
|
+
children = parse_blocks(src2)
|
303
|
+
with_par = want_my_paragraph || (children.size>1)
|
305
304
|
|
306
|
-
|
307
|
-
|
305
|
+
return md_li(children, with_par, al)
|
306
|
+
end
|
308
307
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
308
|
+
def read_abbreviation(src)
|
309
|
+
if not (l=src.shift_line) =~ Abbreviation
|
310
|
+
maruku_error "Bug: it's Andrea's fault. Tell him.\n#{l.inspect}"
|
311
|
+
end
|
313
312
|
|
314
|
-
|
315
|
-
|
313
|
+
abbr = $1
|
314
|
+
desc = $2
|
316
315
|
|
317
|
-
|
318
|
-
|
319
|
-
|
316
|
+
if (not abbr) or (abbr.size==0)
|
317
|
+
maruku_error "Bad abbrev. abbr=#{abbr.inspect} desc=#{desc.inspect}"
|
318
|
+
end
|
320
319
|
|
321
|
-
|
320
|
+
self.abbreviations[abbr] = desc
|
322
321
|
|
323
|
-
|
324
|
-
|
322
|
+
return md_abbr_def(abbr, desc)
|
323
|
+
end
|
325
324
|
|
326
|
-
|
327
|
-
|
325
|
+
def read_footnote_text(src)
|
326
|
+
parent_offset = src.cur_index
|
328
327
|
|
329
|
-
|
328
|
+
first = src.shift_line
|
330
329
|
|
331
|
-
|
332
|
-
|
333
|
-
|
330
|
+
if not first =~ FootnoteText
|
331
|
+
maruku_error "Bug (it's Andrea's fault)"
|
332
|
+
end
|
334
333
|
|
335
|
-
|
336
|
-
|
334
|
+
id = $1
|
335
|
+
text = $2
|
337
336
|
|
338
|
-
|
339
|
-
|
337
|
+
# Ugly things going on inside `read_indented_content`
|
338
|
+
indentation = 4 #first.size-text.size
|
340
339
|
|
341
340
|
# puts "id =_#{id}_; text=_#{text}_ indent=#{indentation}"
|
342
341
|
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
342
|
+
break_list = [:footnote_text, :ref_definition, :definition, :abbreviation]
|
343
|
+
item_type = :footnote_text
|
344
|
+
lines, want_my_paragraph =
|
345
|
+
read_indented_content(src,indentation, break_list, item_type)
|
347
346
|
|
348
|
-
|
349
|
-
|
347
|
+
# add first line
|
348
|
+
if text && text.strip != "" then lines.unshift text end
|
350
349
|
|
351
350
|
# dbg_describe_ary(lines, 'FOOTNOTE')
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
351
|
+
src2 = LineSource.new(lines, src, parent_offset)
|
352
|
+
children = parse_blocks(src2)
|
353
|
+
|
354
|
+
e = md_footnote(id, children)
|
355
|
+
self.footnotes[id] = e
|
356
|
+
return e
|
357
|
+
end
|
358
|
+
|
359
|
+
|
360
|
+
# This is the only ugly function in the code base.
|
361
|
+
# It is used to read list items, descriptions, footnote text
|
362
|
+
def read_indented_content(src, indentation, break_list, item_type)
|
363
|
+
lines =[]
|
364
|
+
# collect all indented lines
|
365
|
+
saw_empty = false; saw_anything_after = false
|
366
|
+
while src.cur_line
|
368
367
|
# puts "Reading indent = #{indentation} #{src.cur_line.inspect}"
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
368
|
+
#puts "#{src.cur_line.md_type} #{src.cur_line.inspect}"
|
369
|
+
if src.cur_line.md_type == :empty
|
370
|
+
saw_empty = true
|
371
|
+
lines << src.shift_line
|
372
|
+
next
|
373
|
+
end
|
374
|
+
|
375
|
+
# after a white line
|
376
|
+
if saw_empty
|
377
|
+
# we expect things to be properly aligned
|
378
|
+
if (ns=number_of_leading_spaces(src.cur_line)) < indentation
|
379
|
+
#puts "breaking for spaces, only #{ns}: #{src.cur_line}"
|
380
|
+
break
|
381
|
+
end
|
382
|
+
saw_anything_after = true
|
383
|
+
else
|
385
384
|
# if src.cur_line[0] != ?\
|
386
|
-
|
385
|
+
break if break_list.include? src.cur_line.md_type
|
387
386
|
# end
|
388
387
|
# break if src.cur_line.md_type != :text
|
389
|
-
|
388
|
+
end
|
390
389
|
|
391
390
|
|
392
|
-
|
393
|
-
|
391
|
+
stripped = strip_indent(src.shift_line, indentation)
|
392
|
+
lines << stripped
|
394
393
|
|
395
|
-
|
394
|
+
#puts "Accepted as #{stripped.inspect}"
|
396
395
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
396
|
+
# You are only required to indent the first line of
|
397
|
+
# a child paragraph.
|
398
|
+
if stripped.md_type == :text
|
399
|
+
while src.cur_line && (src.cur_line.md_type == :text)
|
400
|
+
lines << strip_indent(src.shift_line, indentation)
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
405
404
|
|
406
|
-
|
407
|
-
|
405
|
+
want_my_paragraph = saw_anything_after ||
|
406
|
+
(saw_empty && (src.cur_line && (src.cur_line.md_type == item_type)))
|
408
407
|
|
409
408
|
# dbg_describe_ary(lines, 'LI')
|
410
|
-
|
409
|
+
# create a new context
|
411
410
|
|
412
|
-
|
413
|
-
|
414
|
-
|
411
|
+
while lines.last && (lines.last.md_type == :empty)
|
412
|
+
lines.pop
|
413
|
+
end
|
415
414
|
|
416
|
-
|
417
|
-
|
415
|
+
return lines, want_my_paragraph
|
416
|
+
end
|
418
417
|
|
419
418
|
|
420
|
-
|
421
|
-
|
419
|
+
def read_quote(src)
|
420
|
+
parent_offset = src.cur_index
|
422
421
|
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
422
|
+
lines = []
|
423
|
+
# collect all indented lines
|
424
|
+
while src.cur_line && src.cur_line.md_type == :quote
|
425
|
+
lines << unquote(src.shift_line)
|
426
|
+
end
|
428
427
|
# dbg_describe_ary(lines, 'QUOTE')
|
429
428
|
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
429
|
+
src2 = LineSource.new(lines, src, parent_offset)
|
430
|
+
children = parse_blocks(src2)
|
431
|
+
return md_quote(children)
|
432
|
+
end
|
434
433
|
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
434
|
+
def read_code(src)
|
435
|
+
# collect all indented lines
|
436
|
+
lines = []
|
437
|
+
while src.cur_line && ([:code, :empty].include? src.cur_line.md_type)
|
438
|
+
lines << strip_indent(src.shift_line, 4)
|
439
|
+
end
|
441
440
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
441
|
+
#while lines.last && (lines.last.md_type == :empty )
|
442
|
+
while lines.last && lines.last.strip.size == 0
|
443
|
+
lines.pop
|
444
|
+
end
|
446
445
|
|
447
|
-
|
448
|
-
|
449
|
-
|
446
|
+
while lines.first && lines.first.strip.size == 0
|
447
|
+
lines.shift
|
448
|
+
end
|
450
449
|
|
451
|
-
|
450
|
+
return nil if lines.empty?
|
452
451
|
|
453
|
-
|
452
|
+
source = lines.join("\n")
|
454
453
|
|
455
454
|
# dbg_describe_ary(lines, 'CODE')
|
456
455
|
|
457
|
-
|
458
|
-
|
456
|
+
return md_codeblock(source)
|
457
|
+
end
|
459
458
|
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
459
|
+
# Reads a series of metadata lines with empty lines in between
|
460
|
+
def read_metadata(src)
|
461
|
+
hash = {}
|
462
|
+
while src.cur_line
|
463
|
+
case src.cur_line.md_type
|
464
|
+
when :empty; src.shift_line
|
465
|
+
when :metadata; hash.merge! parse_metadata(src.shift_line)
|
466
|
+
else break
|
467
|
+
end
|
468
|
+
end
|
469
|
+
hash
|
470
|
+
end
|
472
471
|
|
473
472
|
|
474
|
-
|
475
|
-
|
473
|
+
def read_ref_definition(src, out)
|
474
|
+
line = src.shift_line
|
476
475
|
|
477
476
|
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
477
|
+
# if link is incomplete, shift next line
|
478
|
+
if src.cur_line && !([:footnote_text, :ref_definition, :definition, :abbreviation].include? src.cur_line.md_type) &&
|
479
|
+
([1,2,3].include? number_of_leading_spaces(src.cur_line) )
|
480
|
+
line += " "+ src.shift_line
|
481
|
+
end
|
483
482
|
|
484
483
|
# puts "total= #{line}"
|
485
484
|
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
485
|
+
match = LinkRegex.match(line)
|
486
|
+
if not match
|
487
|
+
maruku_error "Link does not respect format: '#{line}'"
|
488
|
+
return
|
489
|
+
end
|
491
490
|
|
492
|
-
|
493
|
-
|
491
|
+
id = match[1]; url = match[2]; title = match[3];
|
492
|
+
id = sanitize_ref_id(id)
|
494
493
|
|
495
|
-
|
494
|
+
hash = self.refs[id] = {:url=>url,:title=>title}
|
496
495
|
|
497
|
-
|
496
|
+
stuff=match[4]
|
498
497
|
|
499
|
-
|
500
|
-
|
498
|
+
if stuff
|
499
|
+
stuff.split.each do |couple|
|
501
500
|
# puts "found #{couple}"
|
502
|
-
|
503
|
-
|
504
|
-
|
501
|
+
k, v = couple.split('=')
|
502
|
+
v ||= ""
|
503
|
+
if v[0,1]=='"' then v = v[1, v.size-2] end
|
505
504
|
# puts "key:_#{k}_ value=_#{v}_"
|
506
|
-
|
507
|
-
|
508
|
-
|
505
|
+
hash[k.to_sym] = v
|
506
|
+
end
|
507
|
+
end
|
509
508
|
# puts hash.inspect
|
510
509
|
|
511
|
-
|
512
|
-
|
510
|
+
out.push md_ref_def(id, url, meta={:title=>title})
|
511
|
+
end
|
513
512
|
|
514
|
-
|
513
|
+
def split_cells(s)
|
515
514
|
# s.strip.split('|').select{|x|x.strip.size>0}.map{|x|x.strip}
|
516
515
|
# changed to allow empty cells
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
516
|
+
s.strip.split('|').select{|x|x.size>0}.map{|x|x.strip}
|
517
|
+
end
|
518
|
+
|
519
|
+
def read_table(src)
|
520
|
+
head = split_cells(src.shift_line).map{|s| md_el(:head_cell, parse_lines_as_span([s])) }
|
521
|
+
|
522
|
+
separator=split_cells(src.shift_line)
|
523
|
+
|
524
|
+
align = separator.map { |s| s =~ Sep
|
525
|
+
if $1 and $2 then :center elsif $2 then :right else :left end }
|
526
|
+
|
527
|
+
num_columns = align.size
|
528
|
+
|
529
|
+
if head.size != num_columns
|
530
|
+
maruku_error "Table head does not have #{num_columns} columns: \n#{head.inspect}"
|
531
|
+
tell_user "I will ignore this table."
|
532
|
+
# XXX try to recover
|
533
|
+
return md_br()
|
534
|
+
end
|
535
|
+
|
536
|
+
rows = []
|
537
|
+
|
538
|
+
while src.cur_line && src.cur_line =~ /\|/
|
539
|
+
row = split_cells(src.shift_line).map{|s|
|
540
|
+
md_el(:cell, parse_lines_as_span([s]))}
|
541
|
+
if head.size != num_columns
|
542
|
+
maruku_error "Row does not have #{num_columns} columns: \n#{row.inspect}"
|
543
|
+
tell_user "I will ignore this table."
|
544
|
+
# XXX try to recover
|
545
|
+
return md_br()
|
546
|
+
end
|
547
|
+
rows << row
|
548
|
+
end
|
549
|
+
|
550
|
+
children = (head+rows).flatten
|
551
|
+
return md_el(:table, children, {:align => align})
|
552
|
+
end
|
553
|
+
|
554
|
+
# If current line is text, a definition list is coming
|
555
|
+
# if 1) text,empty,[text,empty]*,definition
|
556
|
+
|
557
|
+
def eventually_comes_a_def_list(src)
|
558
|
+
future = src.tell_me_the_future
|
559
|
+
ok = future =~ %r{^t+e?d}x
|
561
560
|
# puts "future: #{future} - #{ok}"
|
562
|
-
|
563
|
-
|
561
|
+
ok
|
562
|
+
end
|
564
563
|
|
565
564
|
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
565
|
+
def read_definition(src)
|
566
|
+
# Read one or more terms
|
567
|
+
terms = []
|
568
|
+
while src.cur_line && src.cur_line.md_type == :text
|
569
|
+
terms << md_el(:definition_term, parse_lines_as_span([src.shift_line]))
|
570
|
+
end
|
572
571
|
# dbg_describe_ary(terms, 'DT')
|
573
572
|
|
574
|
-
|
573
|
+
want_my_paragraph = false
|
575
574
|
|
576
|
-
|
575
|
+
raise "Chunky Bacon!" if not src.cur_line
|
577
576
|
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
577
|
+
# one optional empty
|
578
|
+
if src.cur_line.md_type == :empty
|
579
|
+
want_my_paragraph = true
|
580
|
+
src.shift_line
|
581
|
+
end
|
583
582
|
|
584
|
-
|
583
|
+
raise "Chunky Bacon!" if src.cur_line.md_type != :definition
|
585
584
|
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
585
|
+
# Read one or more definitions
|
586
|
+
definitions = []
|
587
|
+
while src.cur_line && src.cur_line.md_type == :definition
|
588
|
+
parent_offset = src.cur_index
|
590
589
|
|
591
|
-
|
592
|
-
|
593
|
-
|
590
|
+
first = src.shift_line
|
591
|
+
first =~ Definition
|
592
|
+
first = $1
|
594
593
|
|
595
|
-
|
594
|
+
# I know, it's ugly!!!
|
596
595
|
|
597
|
-
|
598
|
-
|
599
|
-
|
596
|
+
lines, w_m_p =
|
597
|
+
read_indented_content(src,4, [:definition], :definition)
|
598
|
+
want_my_paragraph ||= w_m_p
|
600
599
|
|
601
|
-
|
600
|
+
lines.unshift first
|
602
601
|
|
603
602
|
# dbg_describe_ary(lines, 'DD')
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
603
|
+
src2 = LineSource.new(lines, src, parent_offset)
|
604
|
+
children = parse_blocks(src2)
|
605
|
+
definitions << md_el(:definition_data, children)
|
606
|
+
end
|
607
|
+
|
608
|
+
return md_el(:definition, terms+definitions, {
|
609
|
+
:terms => terms,
|
610
|
+
:definitions => definitions,
|
611
|
+
:want_my_paragraph => want_my_paragraph})
|
612
|
+
end
|
614
613
|
end # BlockLevelParser
|
615
614
|
end # MaRuKu
|
616
615
|
end
|