class Kramdown::Parser::Kramdown
Public Instance Methods
This helper methods adds the approriate attributes to the element el
of type a
or img
and the element itself to the @tree.
# File lib/monkey_patches/kramdown/parser/kramdown/link.rb, line 6 def add_link(el, href, title, alt_text = nil, ial = nil, link_id = nil) el.options[:ial] = ial el.options[:link_id] = link_id update_attr_with_ial(el.attr, ial) if ial if el.type == :a el.attr['href'] = href el.options[:link_text] = alt_text else el.attr['src'] = href el.attr['alt'] = alt_text el.children.clear end el.attr['title'] = title if title @tree.children << el end
Parse the Atx header at the current location.
# File lib/monkey_patches/kramdown/parser/kramdown/header.rb, line 21 def parse_atx_header return false if !after_block_boundary? 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, :original_text => @src[0].chomp) add_text(text, el) el.attr['id'] = id if id @tree.children << el true end
Parse the autolink at the current location.
# File lib/monkey_patches/kramdown/parser/kramdown/autolink.rb, line 6 def parse_autolink start_line_number = @src.current_line_number @src.pos += @src.matched_size href = (@src[2].nil? ? "mailto:#{@src[1]}" : @src[1]) el = Element.new(:a, nil, {'href' => href}, :location => start_line_number, :raw_text => @src[0].dup) add_text(@src[1].sub(/^mailto:/, ''), el) @tree.children << el end
Parse the blockquote at the current location.
# File lib/monkey_patches/kramdown/parser/kramdown/blockquote.rb, line 6 def parse_blockquote start_line_number = @src.current_line_number result = @src.scan(PARAGRAPH_MATCH) while !@src.match?(self.class::LAZY_END) result << @src.scan(PARAGRAPH_MATCH) end raw_text = result.dup result.gsub!(BLOCKQUOTE_START, '') el = new_block_el(:blockquote, nil, nil, :location => start_line_number, :raw_text => raw_text) @tree.children << el parse_blocks(el, result) true end
Parse the indented codeblock at the current location.
# File lib/monkey_patches/kramdown/parser/kramdown/code_block.rb, line 6 def parse_codeblock start_line_number = @src.current_line_number data = @src.scan(self.class::CODEBLOCK_MATCH) data.gsub!(/\n( {0,3}\S)/, ' \\1') data.gsub!(INDENT, '') @tree.children << new_block_el(:codeblock, data, nil, :location => start_line_number, :raw_text => @src.matched.dup) true end
Parse the fenced codeblock at the current location.
# File lib/monkey_patches/kramdown/parser/kramdown/code_block.rb, line 16 def parse_codeblock_fenced if @src.check(self.class::FENCED_CODEBLOCK_MATCH) start_line_number = @src.current_line_number @src.pos += @src.matched_size el = new_block_el(:codeblock, @src[5], nil, :location => start_line_number, :raw_text => @src.matched.dup) lang = @src[3].to_s.strip unless lang.empty? el.options[:lang] = lang el.attr['class'] = "language-#{@src[4]}" end @tree.children << el true else false end end
Parse the codespan at the current scanner location.
# File lib/monkey_patches/kramdown/parser/kramdown/code_span.rb, line 5 def parse_codespan start_line_number = @src.current_line_number result = @src.scan(CODESPAN_DELIMITER) simple = (result.length == 1) saved_pos = @src.save_pos if simple && @src.pre_match =~ /\s\Z/ && @src.match?(/\s/) add_text(result) return end if text = @src.scan_until(/#{result}/) raw_text = result + text text.sub!(/#{result}\Z/, '') if !simple text = text[1..-1] if text[0..0] == ' ' text = text[0..-2] if text[-1..-1] == ' ' end @tree.children << Element.new(:codespan, text, nil, :location => start_line_number, :raw_text => raw_text) else @src.revert_pos(saved_pos) add_text(result) end end
Parse the emphasis at the current location.
# File lib/monkey_patches/kramdown/parser/kramdown/emphasis.rb, line 6 def parse_emphasis start_line_number = @src.current_line_number saved_pos = @src.save_pos result = @src.scan(EMPHASIS_START) element = (result.length == 2 ? :strong : :em) type = result[0..0] if (type == '_' && @src.pre_match =~ /[[:alpha:]-]\z/) || @src.check(/\s/) || @tree.type == element || @stack.any? { |el, _| el.type == element } add_text(result) return end sub_parse = lambda do |delim, elem| el = Element.new(elem, nil, nil, :location => start_line_number, :delim => delim) stop_re = /#{Regexp.escape(delim)}/ found = parse_spans(el, stop_re) do (@src.pre_match[-1, 1] !~ /\s/) && (elem != :em || !@src.match?(/#{Regexp.escape(delim*2)}(?!#{Regexp.escape(delim)})/)) && (type != '_' || !@src.match?(/#{Regexp.escape(delim)}[[:alnum:]]/)) && el.children.size > 0 end [found, el, stop_re] end found, el, stop_re = sub_parse.call(result, element) if !found && element == :strong && @tree.type != :em @src.revert_pos(saved_pos) @src.pos += 1 found, el, stop_re = sub_parse.call(type, :em) end if found @src.scan(stop_re) @tree.children << el else @src.revert_pos(saved_pos) @src.pos += result.length add_text(result) end end
Parse the backslash-escaped character at the current location.
# File lib/monkey_patches/kramdown/parser/kramdown/escaped_chars.rb, line 6 def parse_escaped_chars @src.pos += @src.matched_size add_text(@src[0]) end
Parse the footnote marker at the current location.
# File lib/monkey_patches/kramdown/parser/kramdown/footnote.rb, line 5 def parse_footnote_marker start_line_number = @src.current_line_number @src.pos += @src.matched_size fn_def = @footnotes[@src[1]] if fn_def if fn_def[:eob] update_attr_with_ial(fn_def[:eob].attr, fn_def[:eob].options[:ial] || {}) fn_def[:attr] = fn_def[:eob].attr fn_def[:options] = fn_def[:eob].options fn_def.delete(:eob) end fn_def[:marker] ||= [] fn_def[:marker].push(Element.new(:footnote, fn_def[:content], fn_def[:attr], fn_def[:options].merge(:name => @src[1], :location => start_line_number, :raw_text => @src[0].dup))) @tree.children << fn_def[:marker].last else warning("Footnote definition for '#{@src[1]}' not found on line #{start_line_number}") add_text(@src.matched) end end
Parse the horizontal rule at the current location.
# File lib/monkey_patches/kramdown/parser/kramdown/horizontal_rule.rb, line 6 def parse_horizontal_rule start_line_number = @src.current_line_number @src.pos += @src.matched_size @tree.children << new_block_el(:hr, nil, nil, :location => start_line_number, raw_text: @src[0].dup) true end
# File lib/monkey_patches/kramdown/parser/kramdown/link.rb, line 23 def parse_link start_line_number = @src.current_line_number result = @src.scan(LINK_START) raw_text = result.dup cur_pos = @src.pos saved_pos = @src.save_pos link_type = (result =~ /^!/ ? :img : :a) # no nested links allowed if link_type == :a && (@tree.type == :img || @tree.type == :a || @stack.any? { |t, s| t && (t.type == :img || t.type == :a) }) add_text(result) return end el = Element.new(link_type, nil, nil, :location => start_line_number) count = 1 found = parse_spans(el, LINK_BRACKET_STOP_RE) do count = count + (@src[1] ? -1 : 1) count - el.children.select { |c| c.type == :img }.size == 0 end unless found @src.revert_pos(saved_pos) add_text(result) return end alt_text = extract_string(cur_pos...@src.pos, @src).gsub(ESCAPED_CHARS, '\1') raw_text << alt_text.dup @src.scan(LINK_BRACKET_STOP_RE) raw_text << @src[0].dup # reference style link or no link url if @src.scan(LINK_INLINE_ID_RE) || !@src.check(/\(/) link_id = normalize_link_id(@src[1] || alt_text) if @link_defs.has_key?(link_id) add_link(el, @link_defs[link_id][0], @link_defs[link_id][1], alt_text, @link_defs[link_id][2] && @link_defs[link_id][2].options[:ial], link_id) else warning("No link definition for link ID '#{link_id}' found on line #{start_line_number}") @src.revert_pos(saved_pos) add_text(result) end raw_text << @src[0].dup unless @src[0].nil? el.options[:raw_text] = raw_text return end # link url in parentheses if @src.scan(/\(<(.*?)>/) link_url = @src[1] if @src.scan(/\)/) raw_text += "(<#{link_url}>)" el.options[:raw_text] = raw_text add_link(el, link_url, nil, alt_text) return end else link_url = '' nr_of_brackets = 0 while temp = @src.scan_until(LINK_PAREN_STOP_RE) link_url << temp if @src[2] nr_of_brackets -= 1 break if nr_of_brackets == 0 elsif @src[1] nr_of_brackets += 1 else break end end raw_text << link_url.dup link_url = link_url[1..-2] link_url.strip! if nr_of_brackets == 0 el.options[:raw_text] = raw_text add_link(el, link_url, nil, alt_text) return end end if @src.scan(LINK_INLINE_TITLE_RE) raw_text << @src[0].dup el.options[:raw_text] = raw_text add_link(el, link_url, @src[0][0..-2], alt_text) else @src.revert_pos(saved_pos) add_text(result) end end
# File lib/monkey_patches/kramdown/parser/kramdown/list.rb, line 4 def parse_list start_line_number = @src.current_line_number type, list_start_re = (@src.check(LIST_START_UL) ? [:ul, LIST_START_UL] : [:ol, LIST_START_OL]) list = new_block_el(type, nil, nil, :location => start_line_number, :raw_text => "") item = nil content_re, lazy_re, indent_re = nil eob_found = false nested_list_found = false last_is_blank = false while !@src.eos? start_line_number = @src.current_line_number if last_is_blank && @src.check(HR_START) break elsif @src.scan(EOB_MARKER) eob_found = true break elsif @src.scan(list_start_re) item = Element.new(:li, nil, nil, :location => start_line_number, :raw_text => @src.matched.dup) list.options[:raw_text] += @src[0] item.value, indentation, content_re, lazy_re, indent_re = parse_first_list_line(@src[1].length, @src[2]) list.children << item item.value.sub!(self.class::LIST_ITEM_IAL) do |match| parse_attribute_list($1, item.options[:ial] ||= {}) '' end list_start_re = (type == :ul ? /^( {0,#{[3, indentation - 1].min}}[+*-])([\t| ].*?\n)/ : /^( {0,#{[3, indentation - 1].min}}\d+\.)([\t| ].*?\n)/) nested_list_found = (item.value =~ LIST_START) last_is_blank = false item.value = [item.value] elsif (result = @src.scan(content_re)) || (!last_is_blank && (result = @src.scan(lazy_re))) result.sub!(/^(\t+)/) { " " * 4 * $1.length } indentation_found = result.sub!(indent_re, '') if !nested_list_found && indentation_found && result =~ LIST_START item.value << '' nested_list_found = true elsif nested_list_found && !indentation_found && result =~ LIST_START result = " " * (indentation + 4) << result end item.options[:raw_text] += @src[0] list.options[:raw_text] += @src[0] item.value.last << result last_is_blank = false elsif result = @src.scan(BLANK_LINE) nested_list_found = true last_is_blank = true item.options[:raw_text] += @src.matched list.options[:raw_text] += @src.matched if list.children.last.type != :blank bl = new_block_el(:blank, [@src.matched.dup]) bl.options[:raw_text] = @src.matched.dup list.children << bl end item.value.last << result else break end end list.options[:raw_text].gsub!(/\R{2,}\z/, "\n") list.children.pop if list.children.last.type == :blank @tree.children << list last = nil list.children.each do |it| temp = Element.new(:temp, nil, nil, :location => it.options[:location]) env = save_env location = it.options[:location] it.value.each do |val| @src = ::Kramdown::Utils::StringScanner.new(val, location) parse_blocks(temp) location = @src.current_line_number end restore_env(env) it.children = temp.children it.value = nil next if it.children.size == 0 # Handle the case where an EOB marker is inserted by a block IAL for the first paragraph it.children.delete_at(1) if it.children.first.type == :p && it.children.length >= 2 && it.children[1].type == :eob && it.children.first.options[:ial] if it.children.first.type == :p && (it.children.length < 2 || it.children[1].type != :blank || (it == list.children.last && it.children.length == 2 && !eob_found)) && (list.children.last != it || list.children.size == 1 || list.children[0..-2].any? { |cit| !cit.children.first || cit.children.first.type != :p || cit.children.first.options[:transparent] }) it.children.first.children.first.value << "\n" if it.children.size > 1 && it.children[1].type != :blank it.children.first.options[:transparent] = true end if it.children.last.type == :blank last = it.children.pop else last = nil end end @tree.children << last if !last.nil? && !eob_found true end
Parse the paragraph at the current location.
# File lib/monkey_patches/kramdown/parser/kramdown/paragraph.rb, line 6 def parse_paragraph start_line_number = @src.current_line_number result = @src.scan(PARAGRAPH_MATCH) while !@src.match?(paragraph_end) result << @src.scan(PARAGRAPH_MATCH) end raw_text = result.dup result.rstrip! if @tree.children.last && @tree.children.last.type == :p @tree.children.last.options[:raw_text] += result @tree.children.last.children.first.value << "\n" << result else @tree.children << new_block_el(:p, nil, nil, :location => start_line_number, raw_text: raw_text) result.lstrip! add_text(result, @tree.children.last) end true end
Parse the Setext header at the current location.
# File lib/monkey_patches/kramdown/parser/kramdown/header.rb, line 6 def parse_setext_header return false if !after_block_boundary? start_line_number = @src.current_line_number @src.pos += @src.matched_size text, id, level = @src[1], @src[2], @src[3] text.strip! el = new_block_el(:header, nil, nil, :level => (level == '-' ? 2 : 1), :raw_text => text, :location => start_line_number, :original_text => @src[0].chomp) add_text(text, el) el.attr['id'] = id if id @tree.children << el true end
Parse the HTML at the current position as span-level HTML.
# File lib/monkey_patches/kramdown/parser/kramdown/html.rb, line 5 def parse_span_html line = @src.current_line_number if result = @src.scan(HTML_COMMENT_RE) @tree.children << Element.new(:xml_comment, result, nil, :category => :span, :location => line) elsif result = @src.scan(HTML_INSTRUCTION_RE) @tree.children << Element.new(:xml_pi, result, nil, :category => :span, :location => line) elsif result = @src.scan(HTML_TAG_CLOSE_RE) warning("Found invalidly used HTML closing tag for '#{@src[1]}' on line #{line}") add_text(result) elsif result = @src.scan(HTML_TAG_RE) tag_name = @src[1] tag_name.downcase! if HTML_ELEMENT[tag_name.downcase] if HTML_BLOCK_ELEMENTS.include?(tag_name) warning("Found block HTML tag '#{tag_name}' in span-level text on line #{line}") add_text(result) return end attrs = parse_html_attributes(@src[2], line, HTML_ELEMENT[tag_name]) attrs.each { |name, value| value.gsub!(/\n+/, ' ') } do_parsing = (HTML_CONTENT_MODEL[tag_name] == :raw || @tree.options[:content_model] == :raw ? false : @options[:parse_span_html]) if val = HTML_MARKDOWN_ATTR_MAP[attrs.delete('markdown')] if val == :block warning("Cannot use block-level parsing in span-level HTML tag (line #{line}) - using default mode") elsif val == :span do_parsing = true elsif val == :default do_parsing = HTML_CONTENT_MODEL[tag_name] != :raw elsif val == :raw do_parsing = false end end el = Element.new(:html_element, tag_name, attrs, :category => :span, :location => line, :content_model => (do_parsing ? :span : :raw), :is_closed => !!@src[4], :opening_tag => result) @tree.children << el stop_re = /<\/#{Regexp.escape(tag_name)}\s*>/ stop_re = Regexp.new(stop_re.source, Regexp::IGNORECASE) if HTML_ELEMENT[tag_name] if !@src[4] && !HTML_ELEMENTS_WITHOUT_BODY.include?(el.value) if parse_spans(el, stop_re, (do_parsing ? nil : [:span_html])) @src.scan(stop_re) else warning("Found no end tag for '#{el.value}' (line #{line}) - auto-closing it") add_text(@src.rest, el) @src.terminate end end Kramdown::Parser::Html::ElementConverter.convert(@root, el) if @options[:html_to_native] else add_text(@src.getch) end end
Parse the typographic symbols at the current location.
# File lib/monkey_patches/kramdown/parser/kramdown/typographic_symbol.rb, line 6 def parse_typographic_syms start_line_number = @src.current_line_number @src.pos += @src.matched_size val = TYPOGRAPHIC_SYMS_SUBST[@src.matched] if val.kind_of?(Symbol) @tree.children << Element.new(:typographic_sym, val, nil, :location => start_line_number, symbol: @src.matched) elsif @src.matched == '\\<<' @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('lt'), nil, :location => start_line_number) @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('lt'), nil, :location => start_line_number) else @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('gt'), nil, :location => start_line_number) @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('gt'), nil, :location => start_line_number) end end