From 0ef9bb00b7f17305396d0cb7640eb080929ccbc9 Mon Sep 17 00:00:00 2001 From: Dan Allen Date: Tue, 20 Feb 2024 04:29:29 -0700 Subject: resolves #3693 don't break nested dlist with attached block if offset from parent list by empty line (PR #4512) --- CHANGELOG.adoc | 1 + lib/asciidoctor/parser.rb | 28 ++++++++++++++++++---------- test/lists_test.rb | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 747371f0..1d98c366 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -74,6 +74,7 @@ Improvements:: Bug Fixes:: * Nested dlist attached using list continuation should not consume detached paragraph (#3535) + * Don't break nested dlist with attached block if offset from parent list by empty line (#3693) * Preserve paragraph breaks in normal table cell in manpage output (#4481) * Style cells in head row as bold in manpage output (#4490) * Escape spaces in include target (using inline passthrough) when generating link from include directive (#4461) diff --git a/lib/asciidoctor/parser.rb b/lib/asciidoctor/parser.rb index 8743b75e..bd1abad1 100644 --- a/lib/asciidoctor/parser.rb +++ b/lib/asciidoctor/parser.rb @@ -44,6 +44,12 @@ class Parser AuthorKeys = ::Set['author', 'authorinitials', 'firstname', 'middlename', 'lastname', 'email'] + ListContinuationMarker = ::Module.new + + ListContinuationPlaceholder = ::String.new.extend ListContinuationMarker + + ListContinuationString = (::String.new LIST_CONTINUATION).extend ListContinuationMarker + # Internal: A Hash mapping horizontal alignment abbreviations to alignments # that can be applied to a table cell (or to all cells in a column) TableCellHorzAlignments = { @@ -1417,17 +1423,18 @@ class Parser # the termination of the list break if is_sibling_list_item? this_line, list_type, sibling_trait + this_line = ListContinuationString if this_line == LIST_CONTINUATION prev_line = buffer.empty? ? nil : buffer[-1] - if prev_line == LIST_CONTINUATION + if ListContinuationMarker === prev_line if continuation == :inactive continuation = :active has_text = true - buffer[-1] = '' unless within_nested_list + buffer[-1] = ListContinuationPlaceholder unless within_nested_list end # dealing with adjacent list continuations (which is really a syntax error) - if this_line == LIST_CONTINUATION + if ListContinuationMarker === this_line if continuation != :frozen continuation = :frozen buffer << this_line @@ -1507,7 +1514,7 @@ class Parser if this_line == LIST_CONTINUATION detached_continuation = buffer.size - buffer << this_line + buffer << ListContinuationString elsif has_text # has_text only relevant for dlist, which is more greedy until it has text for an item; has_text is always true for all other lists # in this block, we have to see whether we stay in the list # TODO any way to combine this with the check after skipping blank lines? @@ -1539,7 +1546,7 @@ class Parser buffer << this_line has_text = true end - elsif this_line == LIST_CONTINUATION + elsif ListContinuationMarker === this_line has_text = true buffer << this_line else @@ -1560,16 +1567,17 @@ class Parser reader.unshift_line this_line if this_line - buffer[detached_continuation] = '' if detached_continuation + buffer[detached_continuation] = ListContinuationPlaceholder if detached_continuation until buffer.empty? + # drop optional trailing continuation + if ListContinuationMarker === (last_line = buffer[-1]) + buffer.pop + break # strip trailing blank lines to prevent empty blocks - if (last_line = buffer[-1]).empty? + elsif last_line.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 diff --git a/test/lists_test.rb b/test/lists_test.rb index e3a1d9da..3dc8b4c6 100644 --- a/test/lists_test.rb +++ b/test/lists_test.rb @@ -3092,6 +3092,24 @@ context 'Description lists (:dlist)' do assert_css '.dlist .paragraph', output, 0 assert_css '.dlist + .paragraph', output, 1 end + + test 'nested dlist with attached block offset by empty line' do + input = <<~'EOS' + category:: + + term 1::: + + + -- + def 1 + -- + EOS + output = convert_string_to_embedded input + assert_xpath '//dl', output, 2 + assert_xpath '//dl//dl', output, 1 + assert_xpath '(//dl)[1]/dt[1][normalize-space(text()) = "category"]', output, 1 + assert_xpath '(//dl)[1]//dl/dt[1][normalize-space(text()) = "term 1"]', output, 1 + assert_xpath '(//dl)[1]//dl/dt[1]/following-sibling::dd//p[starts-with(text(), "def 1")]', output, 1 + end end context 'Special lists' do -- cgit v1.2.3