lib/asciidoctor/parser.rb in asciidoctor-2.0.1 vs lib/asciidoctor/parser.rb in asciidoctor-2.0.2

- old
+ new

@@ -467,30 +467,31 @@ # reader - The Reader from which to retrieve the next Block. # parent - The Document, Section or Block to which the next Block belongs. # attributes - A Hash of attributes that will become the attributes # associated with the parsed Block (default: {}). # options - An options Hash to control parsing (default: {}): - # * :text indicates that the parser is only looking for text content + # * :text_only indicates that the parser is only looking for text content + # * :list_type indicates this block will be attached to a list item in a list of the specified type # # Returns a Block object built from the parsed content of the processed # lines, or nothing if no block is found. def self.next_block(reader, parent, attributes = {}, options = {}) # skip ahead to the block content; bail if we've reached the end of the reader return unless (skipped = reader.skip_blank_lines) # check for option to find list item text only # if skipped a line, assume a list continuation was # used and block content is acceptable - if (text_only = options[:text]) && skipped > 0 - options.delete :text + if (text_only = options[:text_only]) && skipped > 0 + options.delete :text_only text_only = nil end document = parent.document if options.fetch :parse_metadata, true - # read lines until there are no more metadata lines to read + # read lines until there are no more metadata lines to read; note that :text_only option impacts parsing rules while parse_block_metadata_line reader, document, attributes, options # discard the line just processed reader.shift # QUESTION should we clear the attributes? no known cases when it's necessary reader.skip_blank_lines || return @@ -602,11 +603,11 @@ # NOTE assume % units if not specified attributes['scaledwidth'] = (TrailingDigitsRx.match? scaledwidth) ? %(#{scaledwidth}%) : scaledwidth end if attributes['title'] block.title = block_title = attributes.delete 'title' - block.assign_caption (attributes.delete 'caption'), 'figure' + block.assign_caption (attributes.delete 'caption') end end attributes['target'] = target break @@ -720,21 +721,21 @@ reader.unshift_line this_line # a literal paragraph: contiguous lines starting with at least one whitespace character # NOTE style can only be nil or "normal" at this point if indented && !style - lines = read_paragraph_lines reader, (list_item = options[:list_item]) && skipped == 0, skip_line_comments: text_only + lines = read_paragraph_lines reader, (content_adjacent = skipped == 0 ? options[:list_type] : nil), skip_line_comments: text_only adjust_indentation! lines - block = Block.new(parent, :literal, content_model: :verbatim, source: lines, attributes: attributes) - if list_item - # a literal gets special meaning inside of a description list - block.set_option 'listparagraph' - block.default_subs = [] + if text_only || content_adjacent == :dlist + # this block gets folded into the list item text + block = Block.new(parent, :paragraph, content_model: :simple, source: lines, attributes: attributes) + else + block = Block.new(parent, :literal, content_model: :verbatim, source: lines, attributes: attributes) end # a normal paragraph: contiguous non-blank/non-continuation lines (left-indented or normal style) else - lines = read_paragraph_lines reader, skipped == 0 && options[:list_item], skip_line_comments: true + lines = read_paragraph_lines reader, skipped == 0 && options[:list_type], skip_line_comments: true # NOTE don't check indented here since it's extremely rare #if text_only || indented if text_only # if [normal] is used over an indented paragraph, shift content to left margin # QUESTION do we even need to shift since whitespace is normalized by XML in this case? @@ -895,12 +896,12 @@ # FIXME we've got to clean this up, it's horrible! block.source_location = reader.cursor_at_mark if document.sourcemap # FIXME title and caption should be assigned when block is constructed (though we need to handle all cases) if attributes['title'] block.title = block_title = attributes.delete 'title' - if CAPTIONABLE_BLOCKS[block_context = block.context] && document.attributes[%(#{block.context}-caption)] - block.assign_caption (attributes.delete 'caption'), block_context + if (caption_attr_name = CAPTION_ATTR_NAMES[block.context]) && document.attributes[caption_attr_name] + block.assign_caption (attributes.delete 'caption') end end # TODO eventually remove the style attribute from the attributes hash #block.style = attributes.delete 'style' block.style = attributes['style'] @@ -1331,35 +1332,29 @@ list_item.source_location = block_cursor if sourcemap_assignment_deferred # NOTE peek on the other side of any comment lines comment_lines = list_item_reader.skip_line_comments if (subsequent_line = list_item_reader.peek_line) list_item_reader.unshift_lines comment_lines unless comment_lines.empty? - if (continuation_connects_first_block = subsequent_line.empty?) - content_adjacent = false - else + unless subsequent_line.empty? content_adjacent = true # treat lines as paragraph text if continuation does not connect first block (i.e., has_text = nil) has_text = nil unless dlist end - else - # NOTE we have no use for any trailing comment lines we might have found - continuation_connects_first_block = false - content_adjacent = false end # reader is confined to boundaries of list, which means only blocks will be found (no sections) - if (block = next_block(list_item_reader, list_item, {}, text: !has_text, list_item: true)) + if (block = next_block(list_item_reader, list_item, {}, text_only: has_text ? nil : true, list_type: list_type)) list_item.blocks << block end while list_item_reader.has_more_lines? - if (block = next_block(list_item_reader, list_item, {}, list_item: true)) + if (block = next_block(list_item_reader, list_item, {}, list_type: list_type)) list_item.blocks << block end end - list_item.fold_first(continuation_connects_first_block, content_adjacent) + list_item.fold_first if content_adjacent && (first_block = list_item.blocks[0]) && first_block.context == :paragraph end dlist ? [[list_term], (list_item.text? || list_item.blocks? ? list_item : nil)] : list_item end @@ -1535,24 +1530,24 @@ this_line = nil end reader.unshift_line this_line if this_line - if detached_continuation - buffer.delete_at detached_continuation + buffer.delete_at detached_continuation if detached_continuation + + until buffer.empty? + # strip trailing blank lines to prevent empty blocks + if (last_line = buffer[-1]).empty? + buffer.pop + else + # drop optional trailing continuation + # (a blank line would have served the same purpose in the document) + buffer.pop if last_line == LIST_CONTINUATION + break + end end - # strip trailing blank lines to prevent empty blocks - buffer.pop while !buffer.empty? && buffer[-1].empty? - - # We do need to replace the optional trailing continuation - # a blank line would have served the same purpose in the document - buffer.pop if !buffer.empty? && buffer[-1] == LIST_CONTINUATION - - #warn "BUFFER[#{list_type},#{sibling_trait}]>#{buffer.join LF}<BUFFER" - #warn "BUFFER[#{list_type},#{sibling_trait}]>#{buffer.inspect}<BUFFER" - buffer end # Internal: Initialize a new Section object and assign any attributes provided # @@ -1985,11 +1980,11 @@ # # reader - the source reader # document - the current Document # attributes - a Hash of attributes in which any metadata found will be stored (default: {}) # options - a Hash of options to control processing: (default: {}) - # * :text indicates that parser is only looking for text content + # * :text_only indicates that parser is only looking for text content # and thus the block title should not be captured # # returns the Hash of attributes including any metadata found def self.parse_block_metadata_lines reader, document, attributes = {}, options = {} while parse_block_metadata_line reader, document, attributes, options @@ -2014,16 +2009,16 @@ # # reader - the source reader # document - the current Document # attributes - a Hash of attributes in which any metadata found will be stored # options - a Hash of options to control processing: (default: {}) - # * :text indicates the parser is only looking for text content, + # * :text_only indicates the parser is only looking for text content, # thus neither a block title or attribute entry should be captured # # returns true if the line contains metadata, otherwise falsy def self.parse_block_metadata_line reader, document, attributes, options = {} if (next_line = reader.peek_line) && - (options[:text] ? (next_line.start_with? '[', '/') : (normal = next_line.start_with? '[', '.', '/', ':')) + (options[:text_only] ? (next_line.start_with? '[', '/') : (normal = next_line.start_with? '[', '.', '/', ':')) if next_line.start_with? '[' if next_line.start_with? '[[' if (next_line.end_with? ']]') && BlockAnchorRx =~ next_line # NOTE registration of id and reftext is deferred until block is processed attributes['id'] = $1