Module TaskJuggler::RichTextSyntaxRules
In: lib/taskjuggler/RichText/SyntaxRules.rb

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.

Methods

Public Instance methods

[Source]

# File lib/taskjuggler/RichText/SyntaxRules.rb, line 398
    def rule_blankLines
      optional
      repeatable
      pattern(%w( $LINEBREAK ))
      pattern(%w( $SPACE ))
    end

[Source]

# File lib/taskjuggler/RichText/SyntaxRules.rb, line 405
    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

[Source]

# 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

[Source]

# 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

[Source]

# 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

[Source]

# File lib/taskjuggler/RichText/SyntaxRules.rb, line 166
    def rule_bulletList4
      repeatable
      pattern(%w( $BULLET4 !text ), lambda {
        RichTextElement.new(@richTextI, :bulletitem4, @val[1])
      })
    end

[Source]

# File lib/taskjuggler/RichText/SyntaxRules.rb, line 441
    def rule_functionArguments
      optional
      repeatable
      pattern(%w( $ID _= $STRING ), lambda {
        [ @val[0], @val[2] ]
      })
    end

[Source]

# 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

[Source]

# File lib/taskjuggler/RichText/SyntaxRules.rb, line 422
    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

[Source]

# File lib/taskjuggler/RichText/SyntaxRules.rb, line 338
    def rule_moreRefToken
      repeatable
      optional
      pattern(%w( _| !refToken ), lambda {
        @val[1].join
      })
    end

[Source]

# 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

[Source]

# 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

[Source]

# 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

[Source]

# 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

[Source]

# File lib/taskjuggler/RichText/SyntaxRules.rb, line 225
    def rule_paragraph
      pattern(%w( !text ), lambda {
        RichTextElement.new(@richTextI, :paragraph, @val[0])
      })
    end

[Source]

# File lib/taskjuggler/RichText/SyntaxRules.rb, line 371
    def rule_plainText
      repeatable
      optional
      pattern(%w( $WORD !space ), lambda {
        el = RichTextElement.new(@richTextI, :text, @val[0])
        el.appendSpace = !@val[1].nil?
        el
      })
    end

[Source]

# 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

[Source]

# File lib/taskjuggler/RichText/SyntaxRules.rb, line 381
    def rule_plainTextWithQueries
      repeatable
      optional
      pattern(%w( !wordWithQueries !space ), lambda {
        @val[0][-1].appendSpace = true if @val[1]
        @val[0]
      })
    end

[Source]

# File lib/taskjuggler/RichText/SyntaxRules.rb, line 89
    def rule_pre
      repeatable
      pattern(%w( $PRE ), lambda {
        @val[0]
      })
    end

[Source]

# File lib/taskjuggler/RichText/SyntaxRules.rb, line 346
    def rule_refToken
      repeatable
      pattern(%w( $WORD ), lambda {
        @val[0]
      })
    end

This is the entry node.

[Source]

# File lib/taskjuggler/RichText/SyntaxRules.rb, line 33
    def rule_richtext
      pattern(%w( !sections . ), lambda {
        RichTextElement.new(@richTextI, :richtext, @val[0])
      })
    end

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

[Source]

# 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

[Source]

# File lib/taskjuggler/RichText/SyntaxRules.rb, line 39
    def rule_sections
      optional
      repeatable
      pattern(%w( !section !blankLines ), lambda {
        @val[0]
      })
    end

[Source]

# File lib/taskjuggler/RichText/SyntaxRules.rb, line 390
    def rule_space
      optional
      repeatable
      pattern(%w( $SPACE ), lambda {
        true
      })
    end

[Source]

# File lib/taskjuggler/RichText/SyntaxRules.rb, line 231
    def rule_text
      pattern(%w( !textWithSpace ), lambda {
        @val[0].last.appendSpace = false
        @val[0]
      })
    end

[Source]

# 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

[Source]

# 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

[Source]

# 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

[Source]

# 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

[Source]

# 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

[Source]

# 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

[Validate]