asciidoctor-rhrev 1.6.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d50d58f6581222d194cf031114bf6aeb82525b1662e6765c4e24c5c4f0e530cd
4
- data.tar.gz: b45e1e49cc09002e1267c1e31221658ec9aa26a5ca49d4ef9dc8ea3ba857e0d4
3
+ metadata.gz: e9f44d95401427d9f6c7fd320ebc68b8a998956bd4092ea6225d7f46c89d574c
4
+ data.tar.gz: 3d1fe74b24dfda792f2e35549bf73cb7823ee227b3a67cf16af38f003c57459e
5
5
  SHA512:
6
- metadata.gz: 0cf35ff6b4b52a1b9851b8eb103efd5eafc0922f59045d4830b5a390a2a62607060ff79442d5c26e129512efaf06cbd0c4dfc06808f992b14fe3203f94a2e3cf
7
- data.tar.gz: 39ac612cba2f168c9cf4b26eddaea213246d18a90a3b25283b38f82c035756ae78597b01090466ae97ffe644f53f813e8f6b907a7957f5bd4f470d8ecc607e73
6
+ metadata.gz: 2a839f2d707b970ff7eeb8e284743510500f04cbcef2b28fb803d4ad0ae747cf74fce15608f078493cd35b759c0a7e9064a5f603fa3c33a7c306b9fff0fd930f
7
+ data.tar.gz: 563a298805ee6f14ff4209d0174ab6c248fb5e360931b8aead2b91fe6a8abc102c314a511b8635fe0e8f7c4766f77154fce8b0ed5493c298a8d31af9ecbccad3
data/CHANGELOG.adoc CHANGED
@@ -1,5 +1,18 @@
1
1
  = Changelog
2
2
 
3
+ == 1.7.1 (2026-09-02)
4
+
5
+ * Fix two revision-history entries sharing the same start page sorting in the wrong relative order whenever one of them has body content that spans a page break (PDF backend). `Converter#convert_section` correctly reads a section's own starting page via `pdf-page-start`, set by asciidoctor-pdf's own `convert_section` right before the heading itself is inked, but paired it with a `:dest][:y]` value read from `cursor` after `result = super` returns, once the section's whole body (nested content, a large table, anything that can span several physical pages of its own) had already rendered. For a page-spanning section that cursor belongs to whatever page the body finished on, not the section's own start page `pdf-page-start` names, so the two stopped describing the same physical location at all; two entries sharing that start page are ordered by this `y` value alone (`renderer.rb`'s own `entries.sort_by`), and a wrong one can reverse their true top-to-bottom order. Reported directly, with real captured values from a real document, confirming exactly this: a page-spanning section's own `y` secretly belonging to the next physical page, sorting it ahead of another entry that genuinely was higher on their shared page. `ChangeBars#record_section_heading_position`, called unconditionally, not gated on change bars being enabled at all, from `ink_general_heading`/`ink_chapter_title`/`ink_part_title`, the same moment upstream itself captures `pdf-page-start`, right before the heading is actually inked. `Converter#convert_section` reads it back instead of a live post-super cursor, so `page_num` and `y` always describe the section's own start consistently. New regression file, `tests/regression/section-dest-y-page-mismatch.rb`, forces the page-spanning body with an explicit `<<<` page break rather than tuning paragraph-repeat counts against exact font metrics, deterministic regardless of theme or font; confirmed to fail (reversed order) without the fix and pass with it
6
+ * Note: gem-only; the Antora extension (HTML output, no PDF page/cursor concept) is unaffected, npm still bumps concurrently per the standing 1.5.1 policy
7
+
8
+ == 1.7.0 (2026-09-02)
9
+
10
+ * Replace 1.6.0's per-item list change bars with a different design, after real user feedback that the syntax it needed was too heavy: marking one item required a `+` continuation, an attribute line, and a two-line empty open block, four lines to mark a single bullet, far more than every other rhrev-markable construct's own single attribute line. 1.6.0's mechanism (`Converter#propagate_list_item_content_marks`, the attached-continuation-block workaround, `list_item` added to the roll-up contexts) is fully removed, not just superseded
11
+ * Add per-item targeting instead, staying on the list's own existing attribute line: one or more trailing positional attributes name which item(s), by 1-based position, get the bar, `[rhrev1-2="Reworded step two",2]`. Several items and a dash range both work, mixed freely, `[rhrev1-2="Reworded the middle steps",2,4-6]`. No positional attribute at all keeps the exact behavior from every release before 1.6.0: one bar over the whole list. Confirmed directly before this design was picked, not assumed: a bare positional attribute cannot collide with anything AsciiDoc already claims on a list (style, and so on), since Asciidoctor tracks positional index by each entry's own place in the bracket, not by counting unnamed entries only, so a named `rhrev1-2="..."` occupying position 1 never contests a trailing bare position. The revision-history roll-up needs no new code at all: a targeted list is still just a marked list, already one of the existing roll-up contexts, already rolling up to its enclosing section correctly
12
+ * `Converter#convert_list_item` reads the innermost enclosing list's own target set off a stack `Converter#convert_targeted_list` maintains (the same shape `@change_bar_section_stack` already uses for nested sections), not off the list argument directly: for a `dlist` using the `unordered`, `ordered`, or `qanda` style, asciidoctor-pdf synthesizes a brand-new `List` object with no attributes of its own to render through, never the real, marked `dlist` node, so the stack is what carries the real target set down correctly regardless of which path produced the call. A `dlist` using the default or horizontal style has no per-item mechanism to target at all (asciidoctor-pdf renders those inline inside `convert_dlist` itself, no per-entry call to override, the same structural gap table-row-level marking has); a positional entry on one of those two styles falls back to marking the whole block, with a warning, rather than silently doing nothing
13
+ * Fix a bug caught during development, before this ever shipped: `bracket_change_bar`, the shared helper every other bar-inking call site already uses, gates on `change_bar? node`, checking the bracketed node's OWN attributes. A targeted item never carries the mark itself, only the enclosing list does, so reusing `bracket_change_bar` unmodified silently swallowed every targeted item's bar, real rendering showed no bar at all despite the target set correctly including the item's index. `Converter#ink_targeted_list_item_change_bar` is the fix, the same shape minus that gate, since membership in the already-resolved target set answers the "should this bar" question on its own. New regression file, `tests/regression/list-item-target-change-bars.rb`, includes a spy on `ink_change_bar` (the same technique `table-cell-change-bar.rb`'s own manual-mode pagerhref check already establishes) specifically because this exact bug would have passed every other check in the file: the revision-history roll-up is a separate mechanism from bar-inking and stayed correct the whole time the bar itself was silently missing
14
+ * Note: gem-only; the Antora extension (HTML output, no page-margin bar geometry the same way) is unaffected, npm still bumps concurrently per the standing 1.5.1 policy
15
+
3
16
  == 1.6.0 (2026-09-02)
4
17
 
5
18
  * Add per-item change bars and revision-history roll-up for individual items in an unordered or ordered list (PDF backend), previously only possible for a whole marked list. `Converter#convert_list_item` brackets asciidoctor-pdf's own per-item render call (`convert_list` calls it once per item directly, a real granular hook, unlike table rows) the same way the existing paragraph/ulist/olist/dlist overrides already bracket their own whole-block calls. No AsciiDoc syntax attaches a block attribute list directly to a list item's own bullet line, confirmed directly against a real parse: the attribute list is silently dropped, not attached to the item, the list, or anywhere else. The working construct, the same shape as an `a|` table cell's own workaround, is a block attribute list on content the item already legitimately attaches via a `+` continuation. `Converter#propagate_list_item_content_marks` copies a marked carrier block's rhrev attribute onto the enclosing item and strips it from the carrier, at prescan time, before real rendering: the strip matters because `convert_list_item`'s own `traverse_list_item` call renders an item's attached blocks through this same converter, so a left-marked carrier would independently trigger its own bar-inking hook too, a second bad bar. `list_item` is now one of the roll-up contexts, resolved via the same nearest-enclosing-section walk every other roll-up context already uses, reusing that mechanism unchanged. A marked sub-list attached to an item keeps its own independent mark; the new marker-carrier context set deliberately excludes ulist/olist/dlist/list_item so a compound item's own nested sub-list is never swallowed into the parent item's mark. A `dlist` using the `unordered`, `ordered`, or `qanda` style gets the same per-item support, since asciidoctor-pdf itself renders those through synthesized list items routed through the same hook; the default and `horizontal` `dlist` styles render each term and description pair inline with no per-item method call to override, the same category of structural gap table-row-level marking has, not attempted here. Verified directly: a real fixture rendered to PNG shows exactly one bar, spanning only the marked item, not the whole list and not bleeding into neighboring items; the revision-history table shows exactly one bullet for the marked item, nothing from its unmarked siblings. New regression file, `tests/regression/list-item-change-bars.rb`, confirmed to fail (a raised `NoMethodError`) without the fix and pass with it
@@ -62,6 +62,29 @@ module Asciidoctor
62
62
  @change_bar_starts&.delete node
63
63
  end
64
64
 
65
+ # A section's own cursor position at heading-ink time, before its
66
+ # body (potentially spanning several pages) renders. Unconditional,
67
+ # not gated on change bars being enabled at all: Converter#
68
+ # convert_section's own revision-history dest needs this, pairing
69
+ # it with pdf-page-start (also captured at this same moment,
70
+ # upstream's own convert_section, right before the heading ink
71
+ # call this method wraps) so both fields describe the section's
72
+ # own start consistently. A page-spanning section's cursor read
73
+ # after the whole body renders belongs to wherever that body
74
+ # finished, not the section's own start page; two entries sharing
75
+ # the same start page then sort by a y value that was never on
76
+ # that page at all, reversing their true top-to-bottom order,
77
+ # confirmed directly against a real document.
78
+ def record_section_heading_position node
79
+ return unless node.context == :section
80
+ @section_heading_positions ||= {}
81
+ @section_heading_positions[node] = cursor
82
+ end
83
+
84
+ def take_section_heading_position node
85
+ @section_heading_positions&.delete node
86
+ end
87
+
65
88
  # A section's bar covers only its own directly-owned content, not any
66
89
  # nested child sections/chapters: as soon as a child section begins
67
90
  # rendering, close out the bar of every still-open ancestor section
@@ -177,11 +200,13 @@ module Asciidoctor
177
200
  # have settled the page, so this is the first accurate start position.
178
201
  def ink_general_heading node, title, opts = {}
179
202
  record_change_bar_start node if @change_bar_attr && !scratch? && (change_bar? node)
203
+ record_section_heading_position node unless scratch?
180
204
  super
181
205
  end
182
206
 
183
207
  def ink_chapter_title node, title, opts = {}
184
208
  record_change_bar_start node if @change_bar_attr && !scratch? && (change_bar? node)
209
+ record_section_heading_position node unless scratch?
185
210
  super
186
211
  end
187
212
 
@@ -189,6 +214,7 @@ module Asciidoctor
189
214
  # so it must be overridden separately
190
215
  def ink_part_title node, title, opts = {}
191
216
  record_change_bar_start node if @change_bar_attr && !scratch? && (change_bar? node)
217
+ record_section_heading_position node unless scratch?
192
218
  super
193
219
  end
194
220
  end
@@ -1,5 +1,6 @@
1
1
  require 'asciidoctor/pdf' unless defined? Asciidoctor::PDF
2
2
  require 'fileutils'
3
+ require 'set'
3
4
  require_relative 'helpers'
4
5
  require_relative 'catalog'
5
6
  require_relative 'renderer'
@@ -226,6 +227,27 @@ module Asciidoctor
226
227
  # page break. A pre-super page_number would be the page before that
227
228
  # break, one page too low for any chapter-starting section.
228
229
  page_num = ((node.attr 'pdf-page-start') || page_number).to_i
230
+
231
+ # y must describe the same physical location page_num does: the
232
+ # section's own start, not wherever cursor happens to sit once
233
+ # this whole call returns. A section's body can span several
234
+ # pages of its own (nested content, a large table, and so on);
235
+ # a post-super cursor read then belongs to whatever page that
236
+ # body finished on, not page_num's page, and the two stop
237
+ # describing the same point at all. take_section_heading_
238
+ # position (change_bars.rb) captured cursor at the same moment
239
+ # upstream captured pdf-page-start, right before the heading
240
+ # itself was inked, so pairing the two here always describes
241
+ # the section's own start consistently. Reported directly
242
+ # against a real document: two entries sharing the same
243
+ # page_sortable sorted in the wrong relative order, one of
244
+ # them a page-spanning section whose old post-super y actually
245
+ # belonged to the page after the one it was paired with.
246
+ # Falls back to the old post-super cursor only for a section
247
+ # with no heading ink call at all (a hidden title), no worse
248
+ # than before for that one remaining case.
249
+ y_pos = take_section_heading_position(node) || cursor
250
+
229
251
  @anchor_catalog ||= {}
230
252
  @anchor_catalog[node.id] ||= {
231
253
  title: node.title,
@@ -234,10 +256,10 @@ module Asciidoctor
234
256
  context: node.context,
235
257
  level: node.level
236
258
  }
237
- @anchor_catalog[node.id][:dest] = { page: (rhrev_display_page page_num), physical_page: page_num, y: cursor }
259
+ @anchor_catalog[node.id][:dest] = { page: (rhrev_display_page page_num), physical_page: page_num, y: y_pos }
238
260
 
239
261
  # Link destination to page for revision history
240
- revision_history.link_dest_to_page node.id, page_num, (@rhrev_body_start_page || 1), y: cursor
262
+ revision_history.link_dest_to_page node.id, page_num, (@rhrev_body_start_page || 1), y: y_pos
241
263
  end
242
264
 
243
265
  # Start position was captured at heading-ink time (after any page advance)
@@ -399,40 +421,151 @@ module Asciidoctor
399
421
  bracket_change_bar(node) { super }
400
422
  end
401
423
 
424
+ # A list marked with only the change-text attribute, [rhrev1-2="..."],
425
+ # is unchanged from every prior release: bracket_change_bar covers
426
+ # the whole list, one bar, one roll-up bullet.
427
+ #
428
+ # A list marked with one or more trailing positional attributes,
429
+ # [rhrev1-2="...",2] or [rhrev1-2="...",2,4-6], instead targets
430
+ # specific items by their 1-based position: no bar over the whole
431
+ # list, a separate bar for just the named item(s), inked by
432
+ # convert_list_item below. The roll-up bullet is unaffected either
433
+ # way, still the list's own single entry, [rhrev1-2="..."] is read
434
+ # exactly as before.
435
+ #
436
+ # A bare positional attribute cannot collide with a list's own
437
+ # style (ulist [square], olist numbering, and so on): confirmed
438
+ # directly, Asciidoctor tracks positional index by each entry's own
439
+ # place in the bracket, not by counting unnamed entries only, so a
440
+ # named rhrev1-2="..." occupying position 1 never contests the
441
+ # trailing bare position(s) after it.
402
442
  def convert_ulist node
403
- bracket_change_bar(node) { super }
443
+ convert_targeted_list(node) { super }
404
444
  end
405
445
 
406
446
  def convert_olist node
407
- bracket_change_bar(node) { super }
447
+ convert_targeted_list(node) { super }
408
448
  end
409
449
 
450
+ # dlist's unordered/ordered/qanda styles synthesize real ListItem
451
+ # objects and route them through convert_list_item the same as
452
+ # ulist/olist, confirmed directly against asciidoctor-pdf's own
453
+ # source (convert_dlist's own case statement, then convert_list),
454
+ # so per-item targeting reaches them too. The default and
455
+ # horizontal styles render every term/description pair inline
456
+ # inside convert_dlist itself, with no per-entry call to override
457
+ # at all, the same structural gap table-row-level marking has;
458
+ # per-item targets on one of those two styles fall back to marking
459
+ # the whole block instead, with a warning, rather than silently
460
+ # doing nothing.
461
+ DLIST_STYLES_ROUTING_THROUGH_LIST_ITEM = %w(unordered ordered qanda).freeze
462
+
410
463
  def convert_dlist node
411
- bracket_change_bar(node) { super }
464
+ targets = list_item_change_bar_targets node
465
+ if (::Set === targets) && !(DLIST_STYLES_ROUTING_THROUGH_LIST_ITEM.include? node.style)
466
+ log :warn, %(rhrev per-item list marking is not supported for a dlist using the '#{node.style || 'default'}' style; marking the whole block instead)
467
+ targets = :all
468
+ end
469
+ convert_targeted_list(node, targets) { super }
470
+ end
471
+
472
+ # Shared by convert_ulist/convert_olist/convert_dlist: computes the
473
+ # target set (unless the caller, convert_dlist, already resolved
474
+ # it), pushes it so convert_list_item can read the innermost
475
+ # enclosing list's own targets, and either brackets the whole list
476
+ # (targets == :all) or leaves bar-inking to convert_list_item
477
+ # entirely (targets is a real index Set, or nil, not marked at
478
+ # all). The stack, not a single ivar, matters for a list nested
479
+ # inside a marked item's own content: the same shape
480
+ # @change_bar_section_stack already uses for nested sections.
481
+ #
482
+ # Takes the real conversion as a block, not a bare super call
483
+ # inside this method: super here would look for
484
+ # Converter#convert_targeted_list up the ancestor chain, which
485
+ # does not exist, since this method's own name differs from the
486
+ # three real converter entry points calling it. The block, called
487
+ # from inside convert_ulist/convert_olist/convert_dlist
488
+ # themselves, keeps super resolving to the right upstream method,
489
+ # the same reason bracket_change_bar takes a block rather than
490
+ # trying to call super itself.
491
+ def convert_targeted_list node, targets = (list_item_change_bar_targets node)
492
+ @list_change_bar_target_stack ||= []
493
+ @list_change_bar_target_stack.push targets
494
+ if targets == :all
495
+ bracket_change_bar(node) { yield }
496
+ else
497
+ yield
498
+ end
499
+ ensure
500
+ @list_change_bar_target_stack.pop
501
+ end
502
+
503
+ # The target set for the list currently being converted: :all
504
+ # (bar the whole list, the only behavior before this feature
505
+ # existed), nil (not marked for the current revision at all), or a
506
+ # Set of 1-based item positions parsed from one or more trailing
507
+ # positional attributes, expanding an N-M token into a range.
508
+ # Reuses change_bar? for the marked/not-marked check, the same
509
+ # predicate every other bar-inking decision in this file already
510
+ # uses, so this only ever answers for the current revnumber.
511
+ def list_item_change_bar_targets node
512
+ return nil unless change_bar? node
513
+ raw = node.instance_variable_get(:@attributes)
514
+ positional_keys = raw.keys.select {|k| ::Integer === k }.sort
515
+ return :all if positional_keys.empty?
516
+ targets = ::Set.new
517
+ positional_keys.each do |key|
518
+ token = raw[key].to_s
519
+ if (m = /\A(\d+)-(\d+)\z/.match token)
520
+ (m[1].to_i..m[2].to_i).each {|i| targets << i }
521
+ elsif /\A\d+\z/.match? token
522
+ targets << token.to_i
523
+ end
524
+ end
525
+ targets.empty? ? :all : targets
412
526
  end
413
527
 
414
528
  # A single item within a ulist/olist (and a dlist using the
415
- # unordered/ordered/qanda styles, which asciidoctor-pdf itself
416
- # synthesizes into real ListItem objects routed through here the
417
- # same way), rather than the whole list. asciidoctor-pdf's own
418
- # convert_list calls this once per item directly (not through the
419
- # normal node.convert dispatch), a real granular hook, so the same
420
- # bracket_change_bar shape as the nine block types above applies
421
- # unchanged: bare super forwards list/opts along with node
422
- # automatically. The bracket spans traverse_list_item's own call at
423
- # the end of the real convert_list_item, which covers the item's
424
- # marker, its principal text, and any attached continuation content
425
- # together, correct even for a compound, multi-block item.
529
+ # unordered/ordered/qanda styles, real ListItem objects
530
+ # asciidoctor-pdf itself synthesizes and routes through here the
531
+ # same way). Reads the innermost enclosing list's own target set
532
+ # off the top of the stack convert_targeted_list maintains, not
533
+ # off list itself: for a dlist's synthesized styles, list here is
534
+ # a brand-new List object asciidoctor-pdf builds on the fly with
535
+ # no attributes of its own, never the real, marked dlist node, so
536
+ # reading list's own attributes directly would never see the
537
+ # mark. The stack is what carries the real target set down
538
+ # correctly regardless of which path produced this call.
426
539
  #
427
- # A dlist using its default or horizontal style is NOT covered:
428
- # asciidoctor-pdf renders those two styles' term/description pairs
429
- # entirely inline inside convert_dlist itself, with no per-entry
430
- # method call to override, the same category of structural gap
431
- # table-row-level marking has (see LIST_ITEM_MARKER_CARRIER_
432
- # CONTEXTS's own docblock and the project's declined-features
433
- # notes); a bigger, riskier lift, not attempted here.
540
+ # list.items.index node relies on plain object identity, correct
541
+ # here: asciidoctor-pdf's own convert_list passes each item
542
+ # straight from list.items into this method, no copying.
543
+ #
544
+ # Deliberately not bracket_change_bar: its own change_bar? node
545
+ # gate checks the item's OWN attributes, always false here, the
546
+ # mark lives on the enclosing list, never the item. That gate is
547
+ # exactly right for every other bracket_change_bar caller (the
548
+ # node being bracketed is the node that was actually marked); it
549
+ # would silently swallow every targeted item's bar here, caught
550
+ # directly by real rendering showing no bar at all despite the
551
+ # target set correctly including this item's index. ink_targeted_
552
+ # list_item_change_bar mirrors bracket_change_bar's own shape
553
+ # without that gate, since membership in targets already answers
554
+ # the "should this bar" question on its own.
434
555
  def convert_list_item node, list, opts = {}
435
- bracket_change_bar(node) { super }
556
+ targets = @list_change_bar_target_stack&.last
557
+ if (::Set === targets) && (idx = list.items.index node) && (targets.include? idx + 1)
558
+ ink_targeted_list_item_change_bar { super }
559
+ else
560
+ super
561
+ end
562
+ end
563
+
564
+ def ink_targeted_list_item_change_bar
565
+ bar_from = { page: page_number, cursor: cursor } if @change_bar_attr && !scratch?
566
+ result = yield
567
+ ink_change_bar bar_from, { page: page_number, cursor: cursor } if bar_from
568
+ result
436
569
  end
437
570
 
438
571
  def convert_rhrev node
@@ -552,24 +685,7 @@ module Asciidoctor
552
685
  # none yet for the matching revision), rather than needing its own
553
686
  # id, its own destination, or a generated label. See
554
687
  # rollup_child_revision_entries.
555
- #
556
- # list_item is included: enclosing_section's own node.parent walk
557
- # already skips past a marked item's containing ulist/olist/dlist to
558
- # the nearest section correctly, no special-casing needed there. Its
559
- # own mark, however, never arrives via the item's own attributes
560
- # directly, see propagate_list_item_content_marks below.
561
- ROLLUP_CONTEXTS = [:paragraph, :ulist, :olist, :dlist, :list_item, :admonition, :open, :quote, :verse, :sidebar].freeze
562
-
563
- # Contexts propagate_list_item_content_marks accepts as a list
564
- # item's own marker carrier: everything ROLLUP_CONTEXTS covers
565
- # except list_item itself (the item is the propagation target, not
566
- # a valid source) and ulist/olist/dlist (a nested sub-list attached
567
- # to an item already has its own independent, correct mark-and-
568
- # roll-up path via convert_ulist/convert_olist/convert_dlist and
569
- # this same ROLLUP_CONTEXTS walk; swallowing its mark into the
570
- # parent item here would both steal it from the sub-list and give
571
- # the item a mark it never earned).
572
- LIST_ITEM_MARKER_CARRIER_CONTEXTS = (ROLLUP_CONTEXTS - [:list_item, :ulist, :olist, :dlist]).freeze
688
+ ROLLUP_CONTEXTS = [:paragraph, :ulist, :olist, :dlist, :admonition, :open, :quote, :verse, :sidebar].freeze
573
689
 
574
690
  # Walks up from node to its nearest enclosing :section, or nil if
575
691
  # none exists, i.e. node sits in the document preamble. Shared by
@@ -773,60 +889,6 @@ module Asciidoctor
773
889
  end
774
890
  end
775
891
 
776
- # No canonical AsciiDoc syntax attaches a block attribute list
777
- # directly to one list item's own bullet line; confirmed directly
778
- # (Asciidoctor.load, a real fixture): the attribute list is silently
779
- # dropped, not attached to the item, the list, or anywhere else. The
780
- # working construct, the same shape as an a| table cell's own
781
- # workaround, is a block attribute list on content the item already
782
- # legitimately attaches via a `+` continuation:
783
- #
784
- # * Item two
785
- # +
786
- # [rhrev1-2="Added item two"]
787
- # --
788
- # --
789
- #
790
- # or with real visible continuation text instead of an empty open
791
- # block. Copies any rhrev-prefixed attribute from the item's own
792
- # directly-attached marker block onto the item itself, then strips
793
- # it from that block, the same two reasons propagate_cell_content_
794
- # marks strips its own source: convert_list_item's traverse_list_
795
- # item call renders an item's attached blocks through this same
796
- # converter, so a left-marked carrier would independently trigger
797
- # its own bar-inking hook too, and the strip keeps
798
- # node_carries_own_rhrev?/rollup_child_revision_entries from later
799
- # finding and rolling up the same mark a second time from the
800
- # carrier's own now-redundant position in the tree.
801
- #
802
- # Deliberately only the item's own direct children (item.blocks),
803
- # not a recursive descent: a compound item nesting a sub-list of
804
- # its own must not have that sub-list's independent marks stolen
805
- # and reattributed to the outer item, LIST_ITEM_MARKER_CARRIER_
806
- # CONTEXTS excludes ulist/olist/dlist/list_item for exactly this
807
- # reason, restricting a valid carrier to paragraph/admonition/open/
808
- # quote/verse/sidebar.
809
- #
810
- # Must run before rollup_child_revision_entries and before real
811
- # rendering, so the item's own attributes are already in place by
812
- # the time either reads them.
813
- def propagate_list_item_content_marks doc
814
- doc.find_by(context: :list_item).each do |item|
815
- item.blocks.each do |node|
816
- next unless LIST_ITEM_MARKER_CARRIER_CONTEXTS.include? node.context
817
- attr_entries = (node.instance_variable_get(:@attributes) rescue nil)
818
- next if attr_entries.nil? || attr_entries.empty?
819
-
820
- attr_entries.keys.each do |key|
821
- key_str = key.to_s
822
- next unless key_str.start_with?(@revision_prefix)
823
- item.set_attr key_str, attr_entries[key]
824
- node.remove_attr key_str
825
- end
826
- end
827
- end
828
- end
829
-
830
892
  def rollup_table_cell_revision_entries doc
831
893
  doc.find_by(context: :table).each do |table|
832
894
  cells = (table.rows[:head] + table.rows[:body]).flatten
@@ -1059,7 +1121,6 @@ module Asciidoctor
1059
1121
  end
1060
1122
 
1061
1123
  propagate_cell_content_marks doc
1062
- propagate_list_item_content_marks doc
1063
1124
  rollup_child_revision_entries doc
1064
1125
  rollup_table_cell_revision_entries doc
1065
1126
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoctor-rhrev
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - 白一百 baiyibai