Class: Kramdown::Parser::GFM

Inherits:
Kramdown show all
Defined in:
lib/kramdown/parser/gfm.rb

Constant Summary collapse

NON_WORD_RE =
(RUBY_VERSION > "1.9" ? /[^\p{Word}\- \t]/ : /[^\w\- \t]/)
ATX_HEADER_START =
/^\#{1,6}\s/
FENCED_CODEBLOCK_START =
/^[ ]{0,3}[~`]{3,}/
FENCED_CODEBLOCK_MATCH =
/^[ ]{0,3}(([~`]){3,})\s*?((\S+?)(?:\?\S*)?)?\s*?\n(.*?)^[ ]{0,3}\1\2*\s*?\n/m
STRIKETHROUGH_DELIM =
/~~/
STRIKETHROUGH_MATCH =
/#{STRIKETHROUGH_DELIM}[^\s~](.*?)[^\s~]#{STRIKETHROUGH_DELIM}/m
ESCAPED_CHARS_GFM =
/\\([\\.*_+`<>()\[\]{}#!:\|"'\$=\-~])/
PARAGRAPH_END_GFM =
/#{LAZY_END}|#{LIST_START}|#{ATX_HEADER_START}|#{DEFINITION_LIST_START}|#{BLOCKQUOTE_START}|#{FENCED_CODEBLOCK_START}/

Constants inherited from Kramdown

Kramdown::ABBREV_DEFINITION_START, Kramdown::ACHARS, Kramdown::ALD_ANY_CHARS, Kramdown::ALD_CLASS_NAME, Kramdown::ALD_ID_CHARS, Kramdown::ALD_ID_NAME, Kramdown::ALD_START, Kramdown::ALD_TYPE_ANY, Kramdown::ALD_TYPE_CLASS_NAME, Kramdown::ALD_TYPE_ID_NAME, Kramdown::ALD_TYPE_ID_OR_CLASS, Kramdown::ALD_TYPE_ID_OR_CLASS_MULTI, Kramdown::ALD_TYPE_KEY_VALUE_PAIR, Kramdown::ALD_TYPE_REF, Kramdown::ATX_HEADER_MATCH, Kramdown::AUTOLINK_START, Kramdown::AUTOLINK_START_STR, Kramdown::BLANK_LINE, Kramdown::BLOCKQUOTE_START, Kramdown::BLOCK_BOUNDARY, Kramdown::BLOCK_EXTENSIONS_START, Kramdown::BLOCK_MATH_START, Kramdown::CODEBLOCK_MATCH, Kramdown::CODEBLOCK_START, Kramdown::CODESPAN_DELIMITER, Kramdown::DEFINITION_LIST_START, Kramdown::EMPHASIS_START, Kramdown::EOB_MARKER, Kramdown::ESCAPED_CHARS, Kramdown::EXT_BLOCK_START, Kramdown::EXT_BLOCK_STOP_STR, Kramdown::EXT_SPAN_START, Kramdown::EXT_START_STR, Kramdown::EXT_STOP_STR, Kramdown::FOOTNOTE_DEFINITION_START, Kramdown::FOOTNOTE_MARKER_START, Kramdown::HEADER_ID, Kramdown::HR_START, Kramdown::HTML_BLOCK_START, Kramdown::HTML_MARKDOWN_ATTR_MAP, Kramdown::HTML_SPAN_START, Kramdown::IAL_BLOCK, Kramdown::IAL_BLOCK_START, Kramdown::IAL_CLASS_ATTR, Kramdown::IAL_SPAN_START, Kramdown::INLINE_MATH_START, Kramdown::LAZY_END, Kramdown::LAZY_END_HTML_SPAN_ELEMENTS, Kramdown::LAZY_END_HTML_START, Kramdown::LAZY_END_HTML_STOP, Kramdown::LINE_BREAK, Kramdown::LINK_BRACKET_STOP_RE, Kramdown::LINK_DEFINITION_START, Kramdown::LINK_INLINE_ID_RE, Kramdown::LINK_INLINE_TITLE_RE, Kramdown::LINK_PAREN_STOP_RE, Kramdown::LINK_START, Kramdown::LIST_ITEM_IAL, Kramdown::LIST_ITEM_IAL_CHECK, Kramdown::LIST_START, Kramdown::LIST_START_OL, Kramdown::LIST_START_UL, Kramdown::PARAGRAPH_END, Kramdown::PARAGRAPH_MATCH, Kramdown::PARAGRAPH_START, Kramdown::PARSE_FIRST_LIST_LINE_REGEXP_CACHE, Kramdown::SETEXT_HEADER_START, Kramdown::SMART_QUOTES_RE, Kramdown::SPAN_EXTENSIONS_START, Kramdown::SQ_CLOSE, Kramdown::SQ_PUNCT, Kramdown::SQ_RULES, Kramdown::SQ_SUBSTS, Kramdown::TABLE_FSEP_LINE, Kramdown::TABLE_HSEP_ALIGN, Kramdown::TABLE_LINE, Kramdown::TABLE_PIPE_CHECK, Kramdown::TABLE_ROW_LINE, Kramdown::TABLE_SEP_LINE, Kramdown::TABLE_START, Kramdown::TRAILING_WHITESPACE, Kramdown::TYPOGRAPHIC_SYMS, Kramdown::TYPOGRAPHIC_SYMS_RE, Kramdown::TYPOGRAPHIC_SYMS_SUBST

Constants included from Html::Parser

Html::Parser::HTML_RAW_START

Constants included from Html::Constants

Html::Constants::HTML_ATTRIBUTE_RE, Html::Constants::HTML_BLOCK_ELEMENTS, Html::Constants::HTML_COMMENT_RE, Html::Constants::HTML_CONTENT_MODEL, Html::Constants::HTML_CONTENT_MODEL_BLOCK, Html::Constants::HTML_CONTENT_MODEL_RAW, Html::Constants::HTML_CONTENT_MODEL_SPAN, Html::Constants::HTML_DOCTYPE_RE, Html::Constants::HTML_ELEMENT, Html::Constants::HTML_ELEMENTS_WITHOUT_BODY, Html::Constants::HTML_ENTITY_RE, Html::Constants::HTML_INSTRUCTION_RE, Html::Constants::HTML_SPAN_ELEMENTS, Html::Constants::HTML_TAG_CLOSE_RE, Html::Constants::HTML_TAG_RE

Constants included from Kramdown

VERSION

Instance Attribute Summary

Attributes inherited from Base

#options, #root, #source, #warnings

Instance Method Summary collapse

Methods inherited from Kramdown

#add_link, #after_block_boundary?, #before_block_boundary?, #correct_abbreviations_attributes, #handle_extension, #handle_kramdown_html_tag, #normalize_link_id, #parse_abbrev_definition, #parse_attribute_list, #parse_atx_header, #parse_autolink, #parse_blank_line, #parse_block_extensions, #parse_block_html, #parse_block_math, #parse_blockquote, #parse_codeblock, #parse_codeblock_fenced, #parse_codespan, #parse_definition_list, #parse_emphasis, #parse_eob_marker, #parse_escaped_chars, #parse_extension_start_tag, #parse_first_list_line, #parse_footnote_definition, #parse_footnote_marker, #parse_horizontal_rule, #parse_html_entity, #parse_inline_math, #parse_line_break, #parse_link, #parse_link_definition, #parse_list, #parse_paragraph, #parse_setext_header, #parse_smart_quotes, #parse_span_extensions, #parse_span_html, #parse_table, #parse_typographic_syms, #replace_abbreviations, #update_ial_with_ial

Methods included from Html::Parser

#handle_html_start_tag, #handle_raw_html_tag, #parse_html_attributes, #parse_raw_html

Methods included from Kramdown

data_dir

Methods inherited from Base

#adapt_source, #add_text, #extract_string, parse, #warning

Constructor Details

#initialize(source, options) ⇒ GFM

Returns a new instance of GFM.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/kramdown/parser/gfm.rb', line 17

def initialize(source, options)
  super
  @options[:auto_id_stripping] = true
  @id_counter = Hash.new(-1)

  @span_parsers.delete(:line_break) if @options[:hard_wrap]
  if @options[:gfm_quirks].include?(:paragraph_end)
    atx_header_parser = :atx_header_gfm_quirk
    @paragraph_end = self.class::PARAGRAPH_END_GFM
  else
    atx_header_parser = :atx_header_gfm
    @paragraph_end = self.class::PARAGRAPH_END
  end

  {:codeblock_fenced => :codeblock_fenced_gfm,
    :atx_header => atx_header_parser}.each do |current, replacement|
    i = @block_parsers.index(current)
    @block_parsers.delete(current)
    @block_parsers.insert(i, replacement)
  end

  i = @span_parsers.index(:escaped_chars)
  @span_parsers[i] = :escaped_chars_gfm if i
  @span_parsers << :strikethrough_gfm
end

Instance Method Details

#generate_gfm_header_id(text) ⇒ Object



99
100
101
102
103
104
105
106
# File 'lib/kramdown/parser/gfm.rb', line 99

def generate_gfm_header_id(text)
  result = text.downcase
  result.gsub!(NON_WORD_RE, '')
  result.tr!(" \t", '-')
  @id_counter[result] += 1
  result << (@id_counter[result] > 0 ? "-#{@id_counter[result]}" : '')
  @options[:auto_id_prefix] + result
end

#paragraph_endObject



156
157
158
# File 'lib/kramdown/parser/gfm.rb', line 156

def paragraph_end
  @paragraph_end
end

#parseObject



43
44
45
46
# File 'lib/kramdown/parser/gfm.rb', line 43

def parse
  super
  update_elements(@root)
end

#parse_atx_header_gfm_quirkObject

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



113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/kramdown/parser/gfm.rb', line 113

def parse_atx_header_gfm_quirk
  start_line_number = @src.current_line_number
  @src.check(ATX_HEADER_MATCH)
  level, text, id = @src[1], @src[2].to_s.strip, @src[3]
  return false if text.empty?

  @src.pos += @src.matched_size
  el = new_block_el(:header, nil, nil, :level => level.length, :raw_text => text, :location => start_line_number)
  add_text(text, el)
  el.attr['id'] = id if id
  @tree.children << el
  true
end

#parse_strikethrough_gfmObject



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/kramdown/parser/gfm.rb', line 135

def parse_strikethrough_gfm
  line_number = @src.current_line_number

  @src.pos += @src.matched_size
  el = Element.new(:html_element, 'del', {}, :category => :span, :line => line_number)
  @tree.children << el

  env = save_env
  reset_env(:src => Kramdown::Utils::StringScanner.new(@src.matched[2..-3], line_number),
            :text_type => :text)
  parse_spans(el)
  restore_env(env)

  el
end

#update_elements(element) ⇒ Object



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

def update_elements(element)
  element.children.map! do |child|
    if child.type == :text && @options[:hard_wrap] && child.value =~ /\n/
      children = []
      lines = child.value.split(/\n/, -1)
      omit_trailing_br = (Kramdown::Element.category(element) == :block && element.children[-1] == child &&
                          lines[-1].empty?)
      lines.each_with_index do |line, index|
        new_element_options = { :location => child.options[:location] + index }

        children << Element.new(:text, (index > 0 ? "\n#{line}" : line), nil, new_element_options)
        children << Element.new(:br, nil, nil, new_element_options) if index < lines.size - 2 ||
          (index == lines.size - 2 && !omit_trailing_br)
      end
      children
    elsif child.type == :html_element
      child
    elsif child.type == :header && @options[:auto_ids] && !child.attr.has_key?('id')
      child.attr['id'] = generate_gfm_header_id(child.options[:raw_text])
      child
    else
      update_elements(child)
      child
    end
  end.flatten!
end

#update_raw_text(item) ⇒ Object

Update the raw text for automatic ID generation.



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/kramdown/parser/gfm.rb', line 76

def update_raw_text(item)
  raw_text = ''

  append_text = lambda do |child|
    if child.type == :text || child.type == :codespan || child.type ==:math
      raw_text << child.value
    elsif child.type == :entity
      raw_text << child.value.char
    elsif child.type == :smart_quote
      raw_text << ::Kramdown::Utils::Entities.entity(child.value.to_s).char
    elsif child.type == :typographic_sym
      raw_text << ::Kramdown::Utils::Entities.entity(child.value.to_s).char
    else
      child.children.each {|c| append_text.call(c)}
    end
  end

  append_text.call(item)
  item.options[:raw_text] = raw_text
end