# class Kramdown::Parser::GFM

### Constants

ATX_HEADER_START
ESCAPED_CHARS_GFM
FENCED_CODEBLOCK_MATCH
FENCED_CODEBLOCK_START
NON_WORD_RE
PARAGRAPH_END_GFM
STRIKETHROUGH_DELIM
STRIKETHROUGH_MATCH

### Public Class Methods

new(source, options) click to toggle source
Calls superclass method `Kramdown::Parser::Kramdown::new`

       # File lib/kramdown/parser/gfm.rb
    16 def initialize(source, options)
    17   super
    18   @options[:auto_id_stripping] = true
    19   @id_counter = Hash.new(-1)
    20
    21   @span_parsers.delete(:line_break) if @options[:hard_wrap]
    22   @span_parsers.delete(:typographic_syms) if @options[:gfm_quirks].include?(:no_auto_typographic)
    23   if @options[:gfm_quirks].include?(:paragraph_end)
    24     atx_header_parser = :atx_header_gfm_quirk
    25     @paragraph_end = self.class::PARAGRAPH_END_GFM
    26   else
    27     atx_header_parser = :atx_header_gfm
    28     @paragraph_end = self.class::PARAGRAPH_END
    29   end
    30
    31   {:codeblock_fenced => :codeblock_fenced_gfm,
    32     :atx_header => atx_header_parser}.each do |current, replacement|
    33     i = @block_parsers.index(current)
    34     @block_parsers.delete(current)
    35     @block_parsers.insert(i, replacement)
    36   end
    37
    38   i = @span_parsers.index(:escaped_chars)
    39   @span_parsers[i] = :escaped_chars_gfm if i
    40   @span_parsers << :strikethrough_gfm
    41 end

### Public Instance Methods

generate_gfm_header_id(text) click to toggle source

        # File lib/kramdown/parser/gfm.rb
    105 def generate_gfm_header_id(text)
    106   result = text.downcase
    107   result.gsub!(NON_WORD_RE, '')
    108   result.tr!(" \t", '-')
    109   @id_counter[result] += 1
    110   result << (@id_counter[result] > 0 ? "-#{@id_counter[result]}" : '')
    111   @options[:auto_id_prefix] + result
    112 end

paragraph_end() click to toggle source

        # File lib/kramdown/parser/gfm.rb
    181 def paragraph_end
    182   @paragraph_end
    183 end

parse() click to toggle source
Calls superclass method `Kramdown::Parser::Kramdown#parse`

       # File lib/kramdown/parser/gfm.rb
    43 def parse
    44   super
    45   update_elements(@root)
    46 end

parse_atx_header_gfm_quirk() click to toggle source

Copied from kramdown/parser/kramdown/header.rb, removed the first line

        # File lib/kramdown/parser/gfm.rb
    119 def parse_atx_header_gfm_quirk
    120   text, id = parse_header_contents
    121   text.sub!(/[\t ]#+\z/, '') && text.rstrip!
    122   return false if text.empty?
    123   add_header(@src["level"].length, text, id)
    124   true
    125 end

parse_list() click to toggle source

To handle task-lists we override the parse method for lists, converting matching text into checkbox input elements where necessary (as well as applying classes to the ul/ol and li elements).

Calls superclass method `Kramdown::Parser::Kramdown#parse_list`

        # File lib/kramdown/parser/gfm.rb
    153 def parse_list
    154   super
    155   current_list = @tree.children.select{ |element| [:ul, :ol].include?(element.type) }.last
    156
    157   is_tasklist = false
    158   box_unchecked = '<input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />'
    159   box_checked = '<input type="checkbox" class="task-list-item-checkbox" disabled="disabled" checked="checked" />'
    160
    161   current_list.children.each do |li|
    162     next unless li.children.size > 0 && li.children[0].type == :p
    163     # li -> p -> raw_text
    164     checked = li.children[0].children[0].value.gsub!(/\A\s*\[ \]\s+/, box_unchecked)
    165     unchecked = li.children[0].children[0].value.gsub!(/\A\s*\[x\]\s+/i, box_checked)
    166     is_tasklist ||= (!checked.nil? || !unchecked.nil?)
    167
    168     li.attr['class'] = 'task-list-item' if is_tasklist
    169   end
    170
    171   current_list.attr['class'] = 'task-list' if is_tasklist
    172
    173   true
    174 end

parse_strikethrough_gfm() click to toggle source

        # File lib/kramdown/parser/gfm.rb
    135 def parse_strikethrough_gfm
    136   line_number = @src.current_line_number
    137
    138   @src.pos += @src.matched_size
    139   el = Element.new(:html_element, 'del', {}, :category => :span, :line => line_number)
    140   @tree.children << el
    141
    142   env = save_env
    143   reset_env(:src => Kramdown::Utils::StringScanner.new(@src.matched[2..-3], line_number),
    144             :text_type => :text)
    145   parse_spans(el)
    146   restore_env(env)
    147
    148   el
    149 end

update_elements(element) click to toggle source

       # File lib/kramdown/parser/gfm.rb
    48 def update_elements(element)
    49   element.children.map! do |child|
    50     if child.type == :text && @options[:hard_wrap] && child.value =~ /\n/
    51       children = []
    52       lines = child.value.split(/\n/, -1)
    53       omit_trailing_br = (Kramdown::Element.category(element) == :block && element.children[-1] == child &&
    54                           lines[-1].empty?)
    55       lines.each_with_index do |line, index|
    56         new_element_options = { :location => child.options[:location] + index }
    57
    58         children << Element.new(:text, (index > 0 ? "\n#{line}" : line), nil, new_element_options)
    59         children << Element.new(:br, nil, nil, new_element_options) if index < lines.size - 2 ||
    60           (index == lines.size - 2 && !omit_trailing_br)
    61       end
    62       children
    63     elsif child.type == :html_element
    64       child
    65     elsif child.type == :header && @options[:auto_ids] && !child.attr.has_key?('id')
    66       child.attr['id'] = generate_gfm_header_id(child.options[:raw_text])
    67       child
    68     else
    69       update_elements(child)
    70       child
    71     end
    72   end.flatten!
    73 end

update_raw_text(item) click to toggle source

Update the raw text for automatic ID generation.

        # File lib/kramdown/parser/gfm.rb
     76 def update_raw_text(item)
     77   raw_text = ''
     78
     79   append_text = lambda do |child|
     80     if child.type == :text || child.type == :codespan || child.type ==:math
     81       raw_text << child.value
     82     elsif child.type == :entity
     83       raw_text << child.value.char
     84     elsif child.type == :smart_quote
     85       raw_text << ::Kramdown::Utils::Entities.entity(child.value.to_s).char
     86     elsif child.type == :typographic_sym
     87       if child.value == :laquo_space
     88         raw_text << "« "
     89       elsif child.value == :raquo_space
     90         raw_text << " »"
     91       else
     92         raw_text << ::Kramdown::Utils::Entities.entity(child.value.to_s).char
     93       end
     94     else
     95       child.children.each {|c| append_text.call(c)}
     96     end
     97   end
     98
     99   append_text.call(item)
    100   item.options[:raw_text] = raw_text
    101 end