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 +4 -4
- data/CHANGELOG.adoc +13 -0
- data/lib/asciidoctor/rhrev/change_bars.rb +26 -0
- data/lib/asciidoctor/rhrev/converter.rb +158 -97
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e9f44d95401427d9f6c7fd320ebc68b8a998956bd4092ea6225d7f46c89d574c
|
|
4
|
+
data.tar.gz: 3d1fe74b24dfda792f2e35549bf73cb7823ee227b3a67cf16af38f003c57459e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
443
|
+
convert_targeted_list(node) { super }
|
|
404
444
|
end
|
|
405
445
|
|
|
406
446
|
def convert_olist node
|
|
407
|
-
|
|
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
|
-
|
|
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,
|
|
416
|
-
#
|
|
417
|
-
# same way)
|
|
418
|
-
#
|
|
419
|
-
#
|
|
420
|
-
#
|
|
421
|
-
#
|
|
422
|
-
#
|
|
423
|
-
#
|
|
424
|
-
#
|
|
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
|
-
#
|
|
428
|
-
# asciidoctor-pdf
|
|
429
|
-
#
|
|
430
|
-
#
|
|
431
|
-
#
|
|
432
|
-
#
|
|
433
|
-
#
|
|
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
|
-
|
|
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
|
|