Module: TaskJuggler::RichTextSyntaxRules

Included in:
RichTextParser
Defined in:
lib/taskjuggler/RichText/SyntaxRules.rb

Overview

This modules contains the syntax definition for the RichTextParser. The defined syntax aims to be compatible to the most commonly used markup elements of the MediaWiki system. See en.wikipedia.org/wiki/Wikipedia:Cheatsheet for details.

Linebreaks are treated just like spaces as word separators unless it is followed by another newline or any of the start-of-line special characters. These characters start sequences that mark headlines, bullet items and such. The special meaning only gets activated when used at the start of the line.

The parser traverses the input text and creates a tree of RichTextElement objects. This is the intermediate representation that can be converted to the final output format.

Instance Method Summary collapse

Instance Method Details

#rule_blankLinesObject



410
411
412
413
414
415
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 410

def rule_blankLines
  optional
  repeatable
  pattern(%w( $LINEBREAK ))
  pattern(%w( $SPACE ))
end

#rule_blockFunctionObject



417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 417

def rule_blockFunction
  pattern(%w( $BLOCKFUNCSTART $ID !functionArguments $BLOCKFUNCEND ),
          lambda {
    args = {}
    @val[2].each { |arg| args[arg[0]] = arg[1] } if @val[2]
    el = RichTextElement.new(@richTextI, :blockfunc)
    # Data is a 2 element Array with the function name and a Hash for the
    # arguments.
    unless @richTextI.richText.functionHandler(@val[1], true)
      error('bad_block_function',
            "Unsupported block function #{@val[1]}")
    end
    el.data = [@val[1], args ]
    el
  })
end

#rule_bulletList1Object



135
136
137
138
139
140
141
142
143
144
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 135

def rule_bulletList1
  optional
  repeatable
  pattern(%w( $BULLET1 !text ), lambda {
    RichTextElement.new(@richTextI, :bulletitem1, @val[1])
  })
  pattern(%w( !bulletList2 ), lambda {
    RichTextElement.new(@richTextI, :bulletlist2, @val[0])
  })
end

#rule_bulletList2Object



146
147
148
149
150
151
152
153
154
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 146

def rule_bulletList2
  repeatable
  pattern(%w( $BULLET2 !text ), lambda {
    RichTextElement.new(@richTextI, :bulletitem2, @val[1])
  })
  pattern(%w( !bulletList3 ), lambda {
    RichTextElement.new(@richTextI, :bulletlist3, @val[0])
  })
end

#rule_bulletList3Object



156
157
158
159
160
161
162
163
164
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 156

def rule_bulletList3
  repeatable
  pattern(%w( $BULLET3 !text ), lambda {
    RichTextElement.new(@richTextI, :bulletitem3, @val[1])
  })
  pattern(%w( !bulletList4 ), lambda {
    RichTextElement.new(@richTextI, :bulletlist4, @val[0])
  })
end

#rule_bulletList4Object



166
167
168
169
170
171
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 166

def rule_bulletList4
  repeatable
  pattern(%w( $BULLET4 !text ), lambda {
    RichTextElement.new(@richTextI, :bulletitem4, @val[1])
  })
end

#rule_functionArgumentsObject



453
454
455
456
457
458
459
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 453

def rule_functionArguments
  optional
  repeatable
  pattern(%w( $ID _= $STRING ), lambda {
    [ @val[0], @val[2] ]
  })
end

#rule_headlinesObject



74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 74

def rule_headlines
  pattern(%w( !title1 ), lambda {
    @val[0]
  })
  pattern(%w( !title2 ), lambda {
    @val[0]
  })
  pattern(%w( !title3 ), lambda {
    @val[0]
  })
  pattern(%w( !title4 ), lambda {
    @val[0]
  })
end

#rule_htmlBlobObject



395
396
397
398
399
400
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 395

def rule_htmlBlob
  repeatable
  pattern(%w( $HTMLBLOB ), lambda {
    @val[0]
  })
end

#rule_inlineFunctionObject



434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 434

def rule_inlineFunction
  pattern(%w( $INLINEFUNCSTART $ID !functionArguments $INLINEFUNCEND
              !space ),
          lambda {
    args = {}
    @val[2].each { |arg| args[arg[0]] = arg[1] } if @val[2]
    el = RichTextElement.new(@richTextI, :inlinefunc)
    # Data is a 2 element Array with the function name and a Hash for the
    # arguments.
    unless @richTextI.richText.functionHandler(@val[1], false)
      error('bad_inline_function',
            "Unsupported inline function #{@val[1]}")
    end
    el.data = [@val[1], args ]
    el.appendSpace = !@val[4].nil?
    el
  })
end

#rule_moreRefTokenObject



338
339
340
341
342
343
344
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 338

def rule_moreRefToken
  repeatable
  optional
  pattern(%w( _| !refToken ), lambda {
    @val[1].join
  })
end

#rule_numberList1Object



173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 173

def rule_numberList1
  repeatable
  pattern(%w( $NUMBER1 !text !blankLines ), lambda {
    el = RichTextElement.new(@richTextI, :numberitem1, @val[1])
    @numberListCounter[0] += 1
    el.data = @numberListCounter.dup
    el
  })
  pattern(%w( !numberList2 ), lambda {
    @numberListCounter[1, 2] = [ 0, 0 ]
    RichTextElement.new(@richTextI, :numberlist2, @val[0])
  })
end

#rule_numberList2Object



187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 187

def rule_numberList2
  repeatable
  pattern(%w( $NUMBER2 !text !blankLines ), lambda {
    el = RichTextElement.new(@richTextI, :numberitem2, @val[1])
    @numberListCounter[1] += 1
    el.data = @numberListCounter.dup
    el
  })
  pattern(%w( !numberList3 ), lambda {
    @numberListCounter[2] = 0
    RichTextElement.new(@richTextI, :numberlist3, @val[0])
  })
end

#rule_numberList3Object



201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 201

def rule_numberList3
  repeatable
  pattern(%w( $NUMBER3 !text !blankLines ), lambda {
    el = RichTextElement.new(@richTextI, :numberitem3, @val[1])
    @numberListCounter[2] += 1
    el.data = @numberListCounter.dup
    el
  })
  pattern(%w( !numberList4 ), lambda {
    @numberListCounter[3] = 0
    RichTextElement.new(@richTextI, :numberlist4, @val[0])
  })
end

#rule_numberList4Object



215
216
217
218
219
220
221
222
223
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 215

def rule_numberList4
  repeatable
  pattern(%w( $NUMBER4 !text !blankLines ), lambda {
    el = RichTextElement.new(@richTextI, :numberitem4, @val[1])
    @numberListCounter[3] += 1
    el.data = @numberListCounter.dup
    el
  })
end

#rule_paragraphObject



225
226
227
228
229
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 225

def rule_paragraph
  pattern(%w( !text ), lambda {
    RichTextElement.new(@richTextI, :paragraph, @val[0])
  })
end

#rule_plainTextObject



371
372
373
374
375
376
377
378
379
380
381
382
383
384
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 371

def rule_plainText
  repeatable
  optional
  pattern(%w( !htmlBlob !space ), lambda {
    el = RichTextElement.new(@richTextI, :htmlblob, @val[0].join)
    el.appendSpace = !@val[1].nil?
    el
  })
  pattern(%w( $WORD !space ), lambda {
    el = RichTextElement.new(@richTextI, :text, @val[0])
    el.appendSpace = !@val[1].nil?
    el
  })
end


284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 284

def rule_plainTextWithLinks
  pattern(%w( !plainText ), lambda {
    @val[0]
  })
  pattern(%w( $REF !refToken !moreRefToken $REFEND !space ), lambda {
    v1 = @val[1].join
    if v1.index(':')
      protocol, locator = v1.split(':')
    else
      protocol = nil
    end
    el = nil
    if protocol == 'File'
      el = RichTextElement.new(@richTextI, :img)
      unless (index = locator.rindex('.'))
        error('rt_file_no_ext', "File name without extension: #{locator}")
      end
      extension = locator[index + 1..-1].downcase
      unless %w( jpg gif png svg ).include?(extension)
        error('rt_file_bad_ext', "Unsupported file type: #{extension}")
      end
      el.data = img = RichTextImage.new(locator)
      if @val[2]
        @val[2].each do |token|
          if token[0, 4] == 'alt='
            img.altText = token[4..-1]
          elsif %w( top middle bottom baseline sub super text-top
                    text-bottom ).include?(token)
            img.verticalAlign = token
          else
            error('rt_bad_file_option',
                  "Unknown option '#{token}' for file reference " +
                  "#{v1}.")
          end
        end
      end
    else
      val = @val[2] || v1
      el = RichTextElement.new(@richTextI, :ref,
                               RichTextElement.new(@richTextI, :text, val))
      el.data = v1
      el.appendSpace = !@val[4].nil?
    end
    el
  })
  pattern(%w( $HREF !wordWithQueries !space !plainTextWithQueries
              $HREFEND !space ), lambda {
    el = RichTextElement.new(@richTextI, :href, @val[3] || @val[1])
    el.data = RichTextElement.new(@richTextI, :richtext, @val[1])
    el.appendSpace = !@val[5].nil?
    el
  })
end

#rule_plainTextWithQueriesObject



386
387
388
389
390
391
392
393
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 386

def rule_plainTextWithQueries
  repeatable
  optional
  pattern(%w( !wordWithQueries !space ), lambda {
    @val[0][-1].appendSpace = true if @val[1]
    @val[0]
  })
end

#rule_preObject



89
90
91
92
93
94
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 89

def rule_pre
  repeatable
  pattern(%w( $PRE ), lambda {
    @val[0]
  })
end

#rule_refTokenObject



346
347
348
349
350
351
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 346

def rule_refToken
  repeatable
  pattern(%w( $WORD ), lambda {
    @val[0]
  })
end

#rule_richtextObject

This is the entry node.



33
34
35
36
37
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 33

def rule_richtext
  pattern(%w( !sections . ), lambda {
    RichTextElement.new(@richTextI, :richtext, @val[0])
  })
end

#rule_sectionObject

The following syntax elements are all block elements that can span multiple lines.



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 49

def rule_section
  pattern(%w( !headlines ), lambda {
    @val[0]
  })
  pattern(%w( $HLINE ), lambda {
    RichTextElement.new(@richTextI, :hline, @val[0])
  })
  pattern(%w( !paragraph ), lambda {
    @val[0]
  })
  pattern(%w( !pre ), lambda {
    RichTextElement.new(@richTextI, :pre, @val[0].join)
  })
  pattern(%w( !bulletList1 ), lambda {
    RichTextElement.new(@richTextI, :bulletlist1, @val[0])
  })
  pattern(%w( !numberList1 ), lambda {
    @numberListCounter = [ 0, 0, 0, 0 ]
    RichTextElement.new(@richTextI, :numberlist1, @val[0])
  })
  pattern(%w( !blockFunction ), lambda {
    @val[0]
  })
end

#rule_sectionsObject



39
40
41
42
43
44
45
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 39

def rule_sections
  optional
  repeatable
  pattern(%w( !section !blankLines ), lambda {
    @val[0]
  })
end

#rule_spaceObject



402
403
404
405
406
407
408
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 402

def rule_space
  optional
  repeatable
  pattern(%w( $SPACE ), lambda {
    true
  })
end

#rule_textObject



231
232
233
234
235
236
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 231

def rule_text
  pattern(%w( !textWithSpace ), lambda {
    @val[0].last.appendSpace = false
    @val[0]
  })
end

#rule_textWithSpaceObject



238
239
240
241
242
243
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
275
276
277
278
279
280
281
282
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 238

def rule_textWithSpace
  repeatable
  pattern(%w( !plainTextWithLinks ), lambda {
    @val[0]
  })
  pattern(%w( !inlineFunction ), lambda {
    @val[0]
  })
  pattern(%w( $ITALIC !space !plainTextWithLinks $ITALIC !space ), lambda {
    el = RichTextElement.new(@richTextI, :italic, @val[2])
    # Since the italic end marker will disappear we need to make sure
    # there was no space before it.
    @val[2].last.appendSpace = false if @val[2].last
    el.appendSpace = !@val[4].nil?
    el
  })
  pattern(%w( $BOLD !space !plainTextWithLinks $BOLD !space ), lambda {
    el = RichTextElement.new(@richTextI, :bold, @val[2])
    @val[2].last.appendSpace = false if @val[2].last
    el.appendSpace = !@val[4].nil?
    el
  })
  pattern(%w( $CODE !space !plainTextWithLinks $CODE !space ), lambda {
    el = RichTextElement.new(@richTextI, :code, @val[2])
    @val[2].last.appendSpace = false if @val[2].last
    el.appendSpace = !@val[4].nil?
    el
  })
  pattern(%w( $BOLDITALIC !space !plainTextWithLinks $BOLDITALIC !space ),
          lambda {
    el = RichTextElement.new(@richTextI,
                        :bold, RichTextElement.new(@richTextI,
                                                   :italic, @val[2]))
    @val[2].last.appendSpace = false if @val[2].last
    el.appendSpace = !@val[4].nil?
    el
  })
  pattern(%w( $FCOLSTART !space !plainTextWithLinks $FCOLEND !space ),
          lambda {
    el = RichTextElement.new(@richTextI, :fontCol, @val[2])
    el.data = @val[0]
    el.appendSpace = !@val[4].nil?
    el
  })
end

#rule_title1Object



96
97
98
99
100
101
102
103
104
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 96

def rule_title1
  pattern(%w( $TITLE1 !space !text $TITLE1END ), lambda {
    el = RichTextElement.new(@richTextI, :title1, @val[2])
    @sectionCounter[0] += 1
    @sectionCounter[1] = @sectionCounter[2] = 0
    el.data = @sectionCounter.dup
    el
  })
end

#rule_title2Object



106
107
108
109
110
111
112
113
114
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 106

def rule_title2
  pattern(%w( $TITLE2 !space !text $TITLE2END ), lambda {
    el = RichTextElement.new(@richTextI, :title2, @val[2])
    @sectionCounter[1] += 1
    @sectionCounter[2] = 0
    el.data = @sectionCounter.dup
    el
  })
end

#rule_title3Object



116
117
118
119
120
121
122
123
124
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 116

def rule_title3
  pattern(%w( $TITLE3 !space !text $TITLE3END ), lambda {
    el = RichTextElement.new(@richTextI, :title3, @val[2])
    @sectionCounter[2] += 1
    @sectionCounter[3] = 0
    el.data = @sectionCounter.dup
    el
  })
end

#rule_title4Object



126
127
128
129
130
131
132
133
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 126

def rule_title4
  pattern(%w( $TITLE4 !space !text $TITLE4END ), lambda {
    el = RichTextElement.new(@richTextI, :title4, @val[2])
    @sectionCounter[3] += 1
    el.data = @sectionCounter.dup
    el
  })
end

#rule_wordWithQueriesObject



353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/taskjuggler/RichText/SyntaxRules.rb', line 353

def rule_wordWithQueries
  repeatable
  pattern(%w( $WORD ), lambda {
    RichTextElement.new(@richTextI, :text, @val[0])
  })
  pattern(%w( $QUERY ), lambda {
    # The <-attributeID-> syntax is a shortcut for an embedded query
    # inline function. It can only be used within a ReportTableCell
    # context that provides a property and a scope property.
    el = RichTextElement.new(@richTextI, :inlinefunc)
    # Data is a 2 element Array with the function name and a Hash for the
    # arguments.
    el.data = ['query', { 'attribute' => @val[0] } ]
    el
  })

end