lib/kramdown/parser/kramdown/list.rb in kramdown-0.10.0 vs lib/kramdown/parser/kramdown/list.rb in kramdown-0.11.0

- old
+ new

@@ -27,14 +27,16 @@ module Kramdown module Parser class Kramdown + LIST_ITEM_IAL = /^\s*(#{IAL_SPAN_START})?\s*\n/ + # Used for parsing the first line of a list item or a definition, i.e. the line with list item # marker or the definition marker. def parse_first_list_line(indentation, content) - if content =~ /^\s*(#{IAL_SPAN_START})?\s*\n/ + if content =~ LIST_ITEM_IAL indentation = 4 else while content =~ /^ *\t/ temp = content.scan(/^ */).first.length + indentation content.sub!(/^( *)(\t+)/) {$1 + " "*(4 - (temp % 4)) + " "*($2.length - 1)*4} @@ -42,68 +44,63 @@ indentation += content.scan(/^ */).first.length end content.sub!(/^\s*/, '') indent_re = /^ {#{indentation}}/ - content_re = /^(?:(?:\t| {4}){#{indentation / 4}} {#{indentation % 4}}|(?:\t| {4}){#{indentation / 4 + 1}}).*?\n/ - [content, indentation, content_re, indent_re] + content_re = /^(?:(?:\t| {4}){#{indentation / 4}} {#{indentation % 4}}|(?:\t| {4}){#{indentation / 4 + 1}}).*\S.*\n/ + lazy_re = /(?!^ {0,#{[indentation, 3].min}}(?:#{IAL_BLOCK}|#{LAZY_END_HTML_STOP}|#{LAZY_END_HTML_START})).*\S.*\n/ + [content, indentation, content_re, lazy_re, indent_re] end LIST_START_UL = /^(#{OPT_SPACE}[+*-])([\t| ].*?\n)/ LIST_START_OL = /^(#{OPT_SPACE}\d+\.)([\t| ].*?\n)/ LIST_START = /#{LIST_START_UL}|#{LIST_START_OL}/ # Parse the ordered or unordered list at the current location. def parse_list - if @tree.children.last && @tree.children.last.type == :p # last element must not be a paragraph - return false - end - type, list_start_re = (@src.check(LIST_START_UL) ? [:ul, LIST_START_UL] : [:ol, LIST_START_OL]) list = new_block_el(type) item = nil - indent_re = nil - content_re = nil + content_re, lazy_re, indent_re = nil eob_found = false nested_list_found = false + last_is_blank = false while !@src.eos? - if @src.check(HR_START) + 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) - item.value, indentation, content_re, indent_re = parse_first_list_line(@src[1].length, @src[2]) + item.value, indentation, content_re, lazy_re, indent_re = parse_first_list_line(@src[1].length, @src[2]) list.children << item item.value.sub!(/^#{IAL_SPAN_START}\s*/) 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 = false - elsif result = @src.scan(content_re) + nested_list_found = (item.value =~ LIST_START) + last_is_blank = false + elsif (result = @src.scan(content_re)) || (!last_is_blank && (result = @src.scan(lazy_re))) result.sub!(/^(\t+)/) { " "*4*($1 ? $1.length : 0) } result.sub!(indent_re, '') if !nested_list_found && result =~ LIST_START - parse_blocks(item, item.value) - if item.children.length == 1 && item.children.first.type == :p - item.value = '' - else - item.children.clear - end + item.value << "^\n" nested_list_found = true end item.value << result + last_is_blank = false elsif result = @src.scan(BLANK_LINE) nested_list_found = true + last_is_blank = true item.value << result - elsif @src.scan(EOB_MARKER) - eob_found = true - break else break end end @@ -111,16 +108,21 @@ last = nil list.children.each do |it| temp = Element.new(:temp) parse_blocks(temp, it.value) - it.children += temp.children + it.children = temp.children it.value = nil next if it.children.size == 0 - 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)) && + # 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.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 @@ -161,34 +163,39 @@ el.children << Element.new(:raw_text, term) deflist.children << el end item = nil - indent_re = nil - content_re = nil + content_re, lazy_re, indent_re = nil def_start_re = DEFINITION_LIST_START + last_is_blank = false while !@src.eos? if @src.scan(def_start_re) item = Element.new(:dd) item.options[:first_as_para] = first_as_para - item.value, indentation, content_re, indent_re = parse_first_list_line(@src[1].length, @src[2]) + item.value, indentation, content_re, lazy_re, indent_re = parse_first_list_line(@src[1].length, @src[2]) deflist.children << item item.value.sub!(/^#{IAL_SPAN_START}\s*/) do |match| parse_attribute_list($~[1], item.options[:ial] ||= {}) '' end def_start_re = /^( {0,#{[3, indentation - 1].min}}:)([\t| ].*?\n)/ first_as_para = false - elsif result = @src.scan(content_re) + last_is_blank = false + elsif @src.check(EOB_MARKER) + break + elsif (result = @src.scan(content_re)) || (!last_is_blank && (result = @src.scan(lazy_re))) result.sub!(/^(\t+)/) { " "*4*($1 ? $1.length : 0) } result.sub!(indent_re, '') item.value << result first_as_para = false + last_is_blank = false elsif result = @src.scan(BLANK_LINE) first_as_para = true item.value << result + last_is_blank = true else break end end