# -*- coding: utf-8 -*-##--# Copyright (C) 2009-2012 Thomas Leitner <t_leitner@gmx.at>## This file is part of kramdown.## kramdown is free software: you can redistribute it and/or modify# it under the terms of the GNU General Public License as published by# the Free Software Foundation, either version 3 of the License, or# (at your option) any later version.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the# GNU General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program. If not, see <http://www.gnu.org/licenses/>.#++#require'kramdown/parser/kramdown/blank_line'require'kramdown/parser/kramdown/eob'require'kramdown/parser/kramdown/horizontal_rule'require'kramdown/parser/kramdown/extensions'moduleKramdownmoduleParserclassKramdownLIST_ITEM_IAL=/^\s*(?:\{:(?!(?:#{ALD_ID_NAME})?:|\/)(#{ALD_ANY_CHARS}+)\})\s*/LIST_ITEM_IAL_CHECK=/^#{LIST_ITEM_IAL}?\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.defparse_first_list_line(indentation,content)ifcontent=~self.class::LIST_ITEM_IAL_CHECKindentation=4elsewhilecontent=~/^ *\t/temp=content.scan(/^ */).first.length+indentationcontent.sub!(/^( *)(\t+)/){$1<<" "*(4-(temp%4)+($2.length-1)*4)}endindentation+=content.scan(/^ */).first.lengthendcontent.sub!(/^\s*/,'')indent_re=/^ {#{indentation}}/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]endLIST_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.defparse_listtype,list_start_re=(@src.check(LIST_START_UL)?[:ul,LIST_START_UL]:[:ol,LIST_START_OL])list=new_block_el(type)item=nilcontent_re,lazy_re,indent_re=nileob_found=falsenested_list_found=falselast_is_blank=falsewhile!@src.eos?iflast_is_blank&&@src.check(HR_START)breakelsif@src.scan(EOB_MARKER)eob_found=truebreakelsif@src.scan(list_start_re)item=Element.new(:li)item.value,indentation,content_re,lazy_re,indent_re=parse_first_list_line(@src[1].length,@src[2])list.children<<itemitem.value.sub!(self.class::LIST_ITEM_IAL)do|match|parse_attribute_list($1,item.options[:ial]||={})''endlist_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=falseelsif(result=@src.scan(content_re))||(!last_is_blank&&(result=@src.scan(lazy_re)))result.sub!(/^(\t+)/){" "*($1?4*$1.length:0)}result.sub!(indent_re,'')if!nested_list_found&&result=~LIST_STARTitem.value<<"^\n"nested_list_found=trueenditem.value<<resultlast_is_blank=falseelsifresult=@src.scan(BLANK_LINE)nested_list_found=truelast_is_blank=trueitem.value<<resultelsebreakendend@tree.children<<listlast=nillist.children.eachdo|it|temp=Element.new(:temp)parse_blocks(temp,it.value)it.children=temp.childrenit.value=nilnextifit.children.size==0# Handle the case where an EOB marker is inserted by a block IAL for the first paragraphit.children.delete_at(1)ifit.children.first.type==:p&&it.children.length>=2&&it.children[1].type==:eob&&it.children.first.options[:ial]ifit.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"ifit.children.size>1&&it.children[1].type!=:blankit.children.first.options[:transparent]=trueendifit.children.last.type==:blanklast=it.children.popelselast=nilendend@tree.children<<lastif!last.nil?&&!eob_foundtrueenddefine_parser(:list,LIST_START)DEFINITION_LIST_START=/^(#{OPT_SPACE}:)([\t| ].*?\n)/# Parse the ordered or unordered list at the current location.defparse_definition_listchildren=@tree.childrenif!children.last||(children.length==1&&children.last.type!=:p)||(children.length>=2&&children[-1].type!=:p&&(children[-1].type!=:blank||children[-1].value!="\n"||children[-2].type!=:p))returnfalseendfirst_as_para=falsedeflist=new_block_el(:dl)para=@tree.children.popifpara.type==:blankpara=@tree.children.popfirst_as_para=trueendpara.children.first.value.split(/\n/).eachdo|term|el=Element.new(:dt)el.children<<Element.new(:raw_text,term)deflist.children<<elenddeflist.options[:ial]=para.options[:ial]item=nilcontent_re,lazy_re,indent_re=nildef_start_re=DEFINITION_LIST_STARTlast_is_blank=falsewhile!@src.eos?if@src.scan(def_start_re)item=Element.new(:dd)item.options[:first_as_para]=first_as_paraitem.value,indentation,content_re,lazy_re,indent_re=parse_first_list_line(@src[1].length,@src[2])deflist.children<<itemitem.value.sub!(self.class::LIST_ITEM_IAL)do|match|parse_attribute_list($1,item.options[:ial]||={})''enddef_start_re=/^( {0,#{[3,indentation-1].min}}:)([\t| ].*?\n)/first_as_para=falselast_is_blank=falseelsif@src.check(EOB_MARKER)breakelsif(result=@src.scan(content_re))||(!last_is_blank&&(result=@src.scan(lazy_re)))result.sub!(/^(\t+)/){" "*($1?4*$1.length:0)}result.sub!(indent_re,'')item.value<<resultfirst_as_para=falselast_is_blank=falseelsifresult=@src.scan(BLANK_LINE)first_as_para=trueitem.value<<resultlast_is_blank=trueelsebreakendendlast=nildeflist.children.eachdo|it|nextifit.type==:dtparse_blocks(it,it.value)it.value=nilnextifit.children.size==0ifit.children.last.type==:blanklast=it.children.popelselast=nilendifit.children.first&&it.children.first.type==:p&&!it.options.delete(:first_as_para)it.children.first.children.first.value<<"\n"ifit.children.size>1it.children.first.options[:transparent]=trueendendif@tree.children.length>=1&&@tree.children.last.type==:dl@tree.children[-1].children.concat(deflist.children)elsif@tree.children.length>=2&&@tree.children[-1].type==:blank&&@tree.children[-2].type==:dl@tree.children.pop@tree.children[-1].children.concat(deflist.children)else@tree.children<<deflistend@tree.children<<lastif!last.nil?trueenddefine_parser(:definition_list,DEFINITION_LIST_START)endendend