summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.adoc2
-rw-r--r--lib/asciidoctor/parser.rb28
-rw-r--r--test/api_test.rb125
-rw-r--r--test/blocks_test.rb2
-rw-r--r--test/fixtures/lists.adoc96
-rw-r--r--test/lists_test.rb6
6 files changed, 248 insertions, 11 deletions
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index 4aa841e9..b9a9ae2d 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -95,6 +95,8 @@ Bug fixes::
Improvements / Refactoring::
+ * use cursor marks to track lines more accurately; record cursor at the start of each block, list item, or table cell (PR #2701, PR #2547) (@seikichi)
+ * populate source_location property on list items when sourcemap option is set on document (PR #2069) (@mogztter)
* log a warning message if an unterminated delimited block is detected (#1133, PR #2612)
* log a warning when nested section is found inside special section that doesn't support nested sections (#2433, PR #2672)
* read files in binary mode to disable automatic endline coercion (then explicitly coerce to UTF-8) (PR #2583, PR #2694)
diff --git a/lib/asciidoctor/parser.rb b/lib/asciidoctor/parser.rb
index 2295998f..78157615 100644
--- a/lib/asciidoctor/parser.rb
+++ b/lib/asciidoctor/parser.rb
@@ -1258,13 +1258,22 @@ class Parser
# for the parent list Block.
def self.next_list_item(reader, list_block, match, sibling_trait = nil)
if (list_type = list_block.context) == :dlist
+ dlist = true
+ has_text = true unless match[3].nil_or_empty?
list_term = ListItem.new(list_block, match[1])
list_item = ListItem.new(list_block, match[3])
- has_text = true unless match[3].nil_or_empty?
+ if list_block.document.sourcemap
+ list_term.source_location = reader.cursor
+ if has_text
+ list_item.source_location = list_term.source_location
+ else
+ sourcemap_assignment_deferred = true
+ end
+ end
else
- # Create list item using first line as the text of the list item
- list_item = ListItem.new(list_block, (text = match[2]))
has_text = true
+ list_item = ListItem.new(list_block, (text = match[2]))
+ list_item.source_location = reader.cursor if list_block.document.sourcemap
if list_type == :ulist
list_item.marker = (sibling_trait ||= match[1])
if text.start_with?('[') && text.start_with?('[ ] ', '[x] ', '[*] ')
@@ -1282,11 +1291,12 @@ class Parser
end
end
- # first skip the line with the marker / term
+ # first skip the line with the marker / term (it gets put back onto the reader by next_block)
reader.shift
block_cursor = reader.cursor
list_item_reader = Reader.new read_lines_for_list_item(reader, list_type, sibling_trait, has_text), block_cursor
if list_item_reader.has_more_lines?
+ 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)
@@ -1296,7 +1306,7 @@ class Parser
else
content_adjacent = true
# treat lines as paragraph text if continuation does not connect first block (i.e., has_text = nil)
- has_text = nil unless list_type == :dlist
+ has_text = nil unless dlist
end
else
# NOTE we have no use for any trailing comment lines we might have found
@@ -1304,19 +1314,17 @@ class Parser
content_adjacent = false
end
- # only relevant for :dlist
- options = {:text => !has_text}
+ attrs, opts = {}, { :text => !has_text }
# we can look for blocks until lines are exhausted without worrying about
# sections since reader is confined to boundaries of list
- while ((block = next_block list_item_reader, list_item, {}, options) && list_item.blocks << block) ||
- list_item_reader.has_more_lines?
+ while ((block = next_block list_item_reader, list_item, attrs, opts) && list_item.blocks << block) || list_item_reader.has_more_lines?
end
list_item.fold_first(continuation_connects_first_block, content_adjacent)
end
- if list_type == :dlist
+ if dlist
if list_item.text? || list_item.blocks?
[list_term, list_item]
else
diff --git a/test/api_test.rb b/test/api_test.rb
index a40d708f..5ec8fa3e 100644
--- a/test/api_test.rb
+++ b/test/api_test.rb
@@ -283,6 +283,19 @@ content
assert_equal 'sample.asciidoc', last_block.file
assert_equal 23, last_block.lineno
+ list_items = last_block.blocks
+ refute_nil list_items[0].source_location
+ assert_equal 'sample.asciidoc', list_items[0].file
+ assert_equal 23, list_items[0].lineno
+
+ refute_nil list_items[1].source_location
+ assert_equal 'sample.asciidoc', list_items[1].file
+ assert_equal 24, list_items[1].lineno
+
+ refute_nil list_items[2].source_location
+ assert_equal 'sample.asciidoc', list_items[2].file
+ assert_equal 25, list_items[2].lineno
+
doc = Asciidoctor.load_file fixture_path('master.adoc'), :sourcemap => true, :safe => :safe
section_1 = doc.sections[0]
@@ -292,6 +305,118 @@ content
assert_equal 1, section_1.lineno
end
+ test 'wip should track file and line information on list items if sourcemap option is set' do
+ doc = Asciidoctor.load_file fixture_path('lists.adoc'), :sourcemap => true
+
+ first_section = doc.blocks[1]
+
+ unordered_basic_list = first_section.blocks[0]
+ assert_equal 11, unordered_basic_list.lineno
+
+ unordered_basic_list_items = unordered_basic_list.find_by :context => :list_item
+ assert_equal 11, unordered_basic_list_items[0].lineno
+ assert_equal 12, unordered_basic_list_items[1].lineno
+ assert_equal 13, unordered_basic_list_items[2].lineno
+
+ unordered_max_nesting = first_section.blocks[1]
+ assert_equal 16, unordered_max_nesting.lineno
+ unordered_max_nesting_items = unordered_max_nesting.find_by :context => :list_item
+ assert_equal 16, unordered_max_nesting_items[0].lineno
+ assert_equal 17, unordered_max_nesting_items[1].lineno
+ assert_equal 18, unordered_max_nesting_items[2].lineno
+ assert_equal 19, unordered_max_nesting_items[3].lineno
+ assert_equal 20, unordered_max_nesting_items[4].lineno
+ assert_equal 21, unordered_max_nesting_items[5].lineno
+
+ checklist = first_section.blocks[2]
+ assert_equal 24, checklist.lineno
+ checklist_list_items = checklist.find_by :context => :list_item
+ assert_equal 24, checklist_list_items[0].lineno
+ assert_equal 25, checklist_list_items[1].lineno
+ assert_equal 26, checklist_list_items[2].lineno
+ assert_equal 27, checklist_list_items[3].lineno
+
+ ordered_basic = first_section.blocks[3]
+ assert_equal 30, ordered_basic.lineno
+ ordered_basic_list_items = ordered_basic.find_by :context => :list_item
+ assert_equal 30, ordered_basic_list_items[0].lineno
+ assert_equal 31, ordered_basic_list_items[1].lineno
+ assert_equal 32, ordered_basic_list_items[2].lineno
+
+ ordered_nested = first_section.blocks[4]
+ assert_equal 35, ordered_nested.lineno
+ ordered_nested_list_items = ordered_nested.find_by :context => :list_item
+ assert_equal 35, ordered_nested_list_items[0].lineno
+ assert_equal 36, ordered_nested_list_items[1].lineno
+ assert_equal 37, ordered_nested_list_items[2].lineno
+ assert_equal 38, ordered_nested_list_items[3].lineno
+ assert_equal 39, ordered_nested_list_items[4].lineno
+
+ ordered_max_nesting = first_section.blocks[5]
+ assert_equal 42, ordered_max_nesting.lineno
+ ordered_max_nesting_items = ordered_max_nesting.find_by :context => :list_item
+ assert_equal 42, ordered_max_nesting_items[0].lineno
+ assert_equal 43, ordered_max_nesting_items[1].lineno
+ assert_equal 44, ordered_max_nesting_items[2].lineno
+ assert_equal 45, ordered_max_nesting_items[3].lineno
+ assert_equal 46, ordered_max_nesting_items[4].lineno
+ assert_equal 47, ordered_max_nesting_items[5].lineno
+
+ labeled_singleline = first_section.blocks[6]
+ assert_equal 50, labeled_singleline.lineno
+ labeled_singleline_items = labeled_singleline.find_by :context => :list_item
+ assert_equal 50, labeled_singleline_items[0].lineno
+ assert_equal 50, labeled_singleline_items[1].lineno
+ assert_equal 51, labeled_singleline_items[2].lineno
+ assert_equal 51, labeled_singleline_items[3].lineno
+
+ labeled_multiline = first_section.blocks[7]
+ assert_equal 54, labeled_multiline.lineno
+ labeled_multiline_items = labeled_multiline.find_by :context => :list_item
+ assert_equal 54, labeled_multiline_items[0].lineno
+ assert_equal 55, labeled_multiline_items[1].lineno
+ assert_equal 56, labeled_multiline_items[2].lineno
+ assert_equal 57, labeled_multiline_items[3].lineno
+
+ qanda = first_section.blocks[8]
+ assert_equal 61, qanda.lineno
+ qanda_items = qanda.find_by :context => :list_item
+ assert_equal 61, qanda_items[0].lineno
+ assert_equal 62, qanda_items[1].lineno
+ assert_equal 63, qanda_items[2].lineno
+ assert_equal 63, qanda_items[3].lineno
+
+ mixed = first_section.blocks[9]
+ assert_equal 66, mixed.lineno
+ mixed_items = mixed.find_by(:context => :list_item) {|block| block.text? }
+ assert_equal 66, mixed_items[0].lineno
+ assert_equal 67, mixed_items[1].lineno
+ assert_equal 68, mixed_items[2].lineno
+ assert_equal 69, mixed_items[3].lineno
+ assert_equal 70, mixed_items[4].lineno
+ assert_equal 71, mixed_items[5].lineno
+ assert_equal 72, mixed_items[6].lineno
+ assert_equal 73, mixed_items[7].lineno
+ assert_equal 74, mixed_items[8].lineno
+ assert_equal 75, mixed_items[9].lineno
+ assert_equal 77, mixed_items[10].lineno
+ assert_equal 78, mixed_items[11].lineno
+ assert_equal 79, mixed_items[12].lineno
+ assert_equal 80, mixed_items[13].lineno
+ assert_equal 81, mixed_items[14].lineno
+ assert_equal 82, mixed_items[15].lineno
+ assert_equal 83, mixed_items[16].lineno
+
+ unordered_complex_list = first_section.blocks[10]
+ assert_equal 86, unordered_complex_list.lineno
+ unordered_complex_items = unordered_complex_list.find_by :context => :list_item
+ assert_equal 86, unordered_complex_items[0].lineno
+ assert_equal 87, unordered_complex_items[1].lineno
+ assert_equal 88, unordered_complex_items[2].lineno
+ assert_equal 92, unordered_complex_items[3].lineno
+ assert_equal 96, unordered_complex_items[4].lineno
+ end
+
test 'should assign correct source location if section occurs on last line of input' do
input = <<-EOS
= Document Title
diff --git a/test/blocks_test.rb b/test/blocks_test.rb
index 7ca9fc8c..0703d1d3 100644
--- a/test/blocks_test.rb
+++ b/test/blocks_test.rb
@@ -218,7 +218,7 @@ supposed to be after sidebar block, except it got swallowed by block comment
EOS
render_embedded_string input
- assert_message @logger, :WARN, '<stdin>: line 8: unterminated comment block', Hash
+ assert_message @logger, :WARN, '<stdin>: line 5: unterminated comment block', Hash
end
# WARNING if first line of content is a directive, it will get interpretted before we know it's a comment block
diff --git a/test/fixtures/lists.adoc b/test/fixtures/lists.adoc
new file mode 100644
index 00000000..324bcd0d
--- /dev/null
+++ b/test/fixtures/lists.adoc
@@ -0,0 +1,96 @@
+= Document Title
+Doc Writer <thedoc@asciidoctor.org>
+
+Preamble paragraph.
+
+NOTE: This is test, only a test.
+
+== Lists
+
+.Unordered, basic
+* Edgar Allen Poe
+* Sheri S. Tepper
+* Bill Bryson
+
+.Unordered, max nesting
+* level 1
+** level 2
+*** level 3
+**** level 4
+***** level 5
+* level 1
+
+.Checklist
+- [*] checked
+- [x] also checked
+- [ ] not checked
+- normal list item
+
+.Ordered, basic
+. Step 1
+. Step 2
+. Step 3
+
+.Ordered, nested
+. Step 1
+. Step 2
+.. Step 2a
+.. Step 2b
+. Step 3
+
+.Ordered, max nesting
+. level 1
+.. level 2
+... level 3
+.... level 4
+..... level 5
+. level 1
+
+.Labeled, single-line
+first term:: definition of first term
+section term:: definition of second term
+
+.Labeled, multi-line
+first term::
+definition of first term
+second term::
+definition of second term
+
+.Q&A
+[qanda]
+What is Asciidoctor?::
+ An implementation of the AsciiDoc processor in Ruby.
+What is the answer to the Ultimate Question?:: 42
+
+.Mixed
+Operating Systems::
+ Linux:::
+ . Fedora
+ * Desktop
+ . Ubuntu
+ * Desktop
+ * Server
+ BSD:::
+ . FreeBSD
+ . NetBSD
+
+Cloud Providers::
+ PaaS:::
+ . OpenShift
+ . CloudBees
+ IaaS:::
+ . Amazon EC2
+ . Rackspace
+
+.Unordered, complex
+* level 1
+** level 2
+*** level 3
+This is a new line inside an unordered list using {plus} symbol.
+We can even force content to start on a separate line... +
+Amazing, isn't it?
+**** level 4
++
+The {plus} symbol is on a new line.
+
+***** level 5
diff --git a/test/lists_test.rb b/test/lists_test.rb
index f22770cb..2e0a8559 100644
--- a/test/lists_test.rb
+++ b/test/lists_test.rb
@@ -4628,5 +4628,11 @@ listing block in list item 1
assert_equal 1, lists[0].lineno
assert_equal 2, lists[1].lineno
assert_equal 3, lists[2].lineno
+
+ list_items = doc.find_by :context => :list_item
+ assert_equal 1, list_items[0].lineno
+ assert_equal 2, list_items[1].lineno
+ assert_equal 3, list_items[2].lineno
+ assert_equal 4, list_items[3].lineno
end
end