Skip to content

Commit

Permalink
backport fix for #4368 use while loop rather than recursion to locate…
Browse files Browse the repository at this point in the history
… next line to process
  • Loading branch information
mojavelinux committed Apr 18, 2023
1 parent 3be9b6c commit 5625ad9
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Expand Up @@ -30,6 +30,7 @@ Compliance::

Bug Fixes::

* Use while loop rather than recursion to locate next line to process; prevents stack limit error (#4368)
* Avoid matching numeric character references when searching for # in xref target (#4393)
* Use correct selector to collapse margin on first and last child of sidebar
* Don't allow target of include directive to start with a space (to distinguish it from a dlist item) or to end with a space
Expand Down
25 changes: 15 additions & 10 deletions lib/asciidoctor/reader.rb
Expand Up @@ -125,16 +125,21 @@ def next_line_empty?
# Returns the next line of the source data as a String if there are lines remaining.
# Returns nothing if there is no more data.
def peek_line direct = false
if direct || @look_ahead > 0
@unescape_next_line ? ((line = @lines[-1]).slice 1, line.length) : @lines[-1]
elsif @lines.empty?
@look_ahead = 0
nil
else
# FIXME the problem with this approach is that we aren't
# retaining the modified line (hence the @unescape_next_line tweak)
# perhaps we need a stack of proxied lines
(process_line @lines[-1]) || peek_line
while true
next_line = @lines[-1]
if direct || @look_ahead > 0
return @unescape_next_line ? (next_line.slice 1, next_line.length) : next_line
elsif next_line
# FIXME the problem with this approach is that we aren't
# retaining the modified line (hence the @unescape_next_line tweak)
# perhaps we need a stack of proxied lines
if (line = process_line next_line)
return line
end
else
@look_ahead = 0
return
end
end
end

Expand Down
37 changes: 37 additions & 0 deletions test/reader_test.rb
Expand Up @@ -145,6 +145,10 @@ class ReaderTest < Minitest::Test
assert reader.next_line_empty?
end

test 'peek_line should return nil if next entry is nil' do
assert_nil (Asciidoctor::Reader.new [nil]).peek_line
end

test 'peek_line should return next line if there are lines remaining' do
reader = Asciidoctor::Reader.new SAMPLE_DATA
assert_equal SAMPLE_DATA.first, reader.peek_line
Expand Down Expand Up @@ -2841,6 +2845,39 @@ def process reader, target, attributes
assert_empty logger
end
end

test 'should not fail to process preprocessor directive that evaluates to false and has a large number of lines' do
lines = (%w(data) * 5000) * ?\n
input = <<~EOS
before
ifdef::attribute-not-set[]
#{lines}
endif::attribute-not-set[]
after
EOS

doc = Asciidoctor.load input
assert_equal 2, doc.blocks.size
assert_equal 'before', doc.blocks[0].source
assert_equal 'after', doc.blocks[1].source
end

test 'should not fail to process lines if reader contains a nil entry' do
input = ['before', '', '', '', 'after']
doc = Asciidoctor.load input, extensions: proc {
preprocessor do
process do |_, reader|
reader.source_lines[2] = nil
nil
end
end
}
assert_equal 2, doc.blocks.size
assert_equal 'before', doc.blocks[0].source
assert_equal 'after', doc.blocks[1].source
end
end
end
end

0 comments on commit 5625ad9

Please sign in to comment.