asciidoctor-rhrev 1.5.3 → 1.7.0
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/converter.rb +139 -3
- 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: 7ff948e637bb99f9d64376d94ad293310988680a558ef3796aa797911210ad48
|
|
4
|
+
data.tar.gz: f47c7b2ecf6aa55d7e396b44221e8d7af6445c9c6085a71182e8b0a457e09226
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a908055a506c6d32629d381a800c2c8911e649e0d4dfcd51ea2b5bb64a7d70e6bd4bb45229541947b9e840df95a9c3335d03179634cfe8efd99d51bedc8a5cb5
|
|
7
|
+
data.tar.gz: 8f5442540754978416479cf2b90f01d207993659b9e243277cdc1d645475dec294379691b62b88d1b7ad55ef3748f4af318486ea3bc7fc3ee6d6e08e2cf3d74b
|
data/CHANGELOG.adoc
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
= Changelog
|
|
2
2
|
|
|
3
|
+
== 1.7.0 (2026-09-02)
|
|
4
|
+
|
|
5
|
+
* 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
|
|
6
|
+
* 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
|
|
7
|
+
* `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
|
|
8
|
+
* 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
|
|
9
|
+
* 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
|
|
10
|
+
|
|
11
|
+
== 1.6.0 (2026-09-02)
|
|
12
|
+
|
|
13
|
+
* 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
|
|
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.5.3 (2026-09-01)
|
|
4
17
|
|
|
5
18
|
* Fix `page_numbering_start_at: cover` still reporting the revision-history table and `pagerhref:` one page low when the theme has no real `front-cover-image`/`cover_front_image` of its own, for example a theme that draws its own cover through some other means. `Converter#compute_rhrev_page_numbering_start_page`'s `cover` branch fell back to plain `body_start` whenever `resolve_background_image` found nothing, matching 1.5.2's own `body`-shaped formula rather than the real one: asciidoctor-pdf itself falls back from `cover` to `title` in that case, not to `body`, and `title`'s own offset is 0 whenever the document has a title page at all (`doctype: book`, or the `title-page` attribute), regardless of whether a real front cover ever rendered. `body_start` only remains correct for the narrow remaining case of no front cover and no title page either. Reported directly against a real document: the table was one page low throughout. New regression case, `cover-no-image`, in `tests/regression/rhrev-page-numbering-start-at.rb`, confirmed to fail without the fix and pass with it
|
|
@@ -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'
|
|
@@ -399,16 +400,151 @@ module Asciidoctor
|
|
|
399
400
|
bracket_change_bar(node) { super }
|
|
400
401
|
end
|
|
401
402
|
|
|
403
|
+
# A list marked with only the change-text attribute, [rhrev1-2="..."],
|
|
404
|
+
# is unchanged from every prior release: bracket_change_bar covers
|
|
405
|
+
# the whole list, one bar, one roll-up bullet.
|
|
406
|
+
#
|
|
407
|
+
# A list marked with one or more trailing positional attributes,
|
|
408
|
+
# [rhrev1-2="...",2] or [rhrev1-2="...",2,4-6], instead targets
|
|
409
|
+
# specific items by their 1-based position: no bar over the whole
|
|
410
|
+
# list, a separate bar for just the named item(s), inked by
|
|
411
|
+
# convert_list_item below. The roll-up bullet is unaffected either
|
|
412
|
+
# way, still the list's own single entry, [rhrev1-2="..."] is read
|
|
413
|
+
# exactly as before.
|
|
414
|
+
#
|
|
415
|
+
# A bare positional attribute cannot collide with a list's own
|
|
416
|
+
# style (ulist [square], olist numbering, and so on): confirmed
|
|
417
|
+
# directly, Asciidoctor tracks positional index by each entry's own
|
|
418
|
+
# place in the bracket, not by counting unnamed entries only, so a
|
|
419
|
+
# named rhrev1-2="..." occupying position 1 never contests the
|
|
420
|
+
# trailing bare position(s) after it.
|
|
402
421
|
def convert_ulist node
|
|
403
|
-
|
|
422
|
+
convert_targeted_list(node) { super }
|
|
404
423
|
end
|
|
405
424
|
|
|
406
425
|
def convert_olist node
|
|
407
|
-
|
|
426
|
+
convert_targeted_list(node) { super }
|
|
408
427
|
end
|
|
409
428
|
|
|
429
|
+
# dlist's unordered/ordered/qanda styles synthesize real ListItem
|
|
430
|
+
# objects and route them through convert_list_item the same as
|
|
431
|
+
# ulist/olist, confirmed directly against asciidoctor-pdf's own
|
|
432
|
+
# source (convert_dlist's own case statement, then convert_list),
|
|
433
|
+
# so per-item targeting reaches them too. The default and
|
|
434
|
+
# horizontal styles render every term/description pair inline
|
|
435
|
+
# inside convert_dlist itself, with no per-entry call to override
|
|
436
|
+
# at all, the same structural gap table-row-level marking has;
|
|
437
|
+
# per-item targets on one of those two styles fall back to marking
|
|
438
|
+
# the whole block instead, with a warning, rather than silently
|
|
439
|
+
# doing nothing.
|
|
440
|
+
DLIST_STYLES_ROUTING_THROUGH_LIST_ITEM = %w(unordered ordered qanda).freeze
|
|
441
|
+
|
|
410
442
|
def convert_dlist node
|
|
411
|
-
|
|
443
|
+
targets = list_item_change_bar_targets node
|
|
444
|
+
if (::Set === targets) && !(DLIST_STYLES_ROUTING_THROUGH_LIST_ITEM.include? node.style)
|
|
445
|
+
log :warn, %(rhrev per-item list marking is not supported for a dlist using the '#{node.style || 'default'}' style; marking the whole block instead)
|
|
446
|
+
targets = :all
|
|
447
|
+
end
|
|
448
|
+
convert_targeted_list(node, targets) { super }
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
# Shared by convert_ulist/convert_olist/convert_dlist: computes the
|
|
452
|
+
# target set (unless the caller, convert_dlist, already resolved
|
|
453
|
+
# it), pushes it so convert_list_item can read the innermost
|
|
454
|
+
# enclosing list's own targets, and either brackets the whole list
|
|
455
|
+
# (targets == :all) or leaves bar-inking to convert_list_item
|
|
456
|
+
# entirely (targets is a real index Set, or nil, not marked at
|
|
457
|
+
# all). The stack, not a single ivar, matters for a list nested
|
|
458
|
+
# inside a marked item's own content: the same shape
|
|
459
|
+
# @change_bar_section_stack already uses for nested sections.
|
|
460
|
+
#
|
|
461
|
+
# Takes the real conversion as a block, not a bare super call
|
|
462
|
+
# inside this method: super here would look for
|
|
463
|
+
# Converter#convert_targeted_list up the ancestor chain, which
|
|
464
|
+
# does not exist, since this method's own name differs from the
|
|
465
|
+
# three real converter entry points calling it. The block, called
|
|
466
|
+
# from inside convert_ulist/convert_olist/convert_dlist
|
|
467
|
+
# themselves, keeps super resolving to the right upstream method,
|
|
468
|
+
# the same reason bracket_change_bar takes a block rather than
|
|
469
|
+
# trying to call super itself.
|
|
470
|
+
def convert_targeted_list node, targets = (list_item_change_bar_targets node)
|
|
471
|
+
@list_change_bar_target_stack ||= []
|
|
472
|
+
@list_change_bar_target_stack.push targets
|
|
473
|
+
if targets == :all
|
|
474
|
+
bracket_change_bar(node) { yield }
|
|
475
|
+
else
|
|
476
|
+
yield
|
|
477
|
+
end
|
|
478
|
+
ensure
|
|
479
|
+
@list_change_bar_target_stack.pop
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
# The target set for the list currently being converted: :all
|
|
483
|
+
# (bar the whole list, the only behavior before this feature
|
|
484
|
+
# existed), nil (not marked for the current revision at all), or a
|
|
485
|
+
# Set of 1-based item positions parsed from one or more trailing
|
|
486
|
+
# positional attributes, expanding an N-M token into a range.
|
|
487
|
+
# Reuses change_bar? for the marked/not-marked check, the same
|
|
488
|
+
# predicate every other bar-inking decision in this file already
|
|
489
|
+
# uses, so this only ever answers for the current revnumber.
|
|
490
|
+
def list_item_change_bar_targets node
|
|
491
|
+
return nil unless change_bar? node
|
|
492
|
+
raw = node.instance_variable_get(:@attributes)
|
|
493
|
+
positional_keys = raw.keys.select {|k| ::Integer === k }.sort
|
|
494
|
+
return :all if positional_keys.empty?
|
|
495
|
+
targets = ::Set.new
|
|
496
|
+
positional_keys.each do |key|
|
|
497
|
+
token = raw[key].to_s
|
|
498
|
+
if (m = /\A(\d+)-(\d+)\z/.match token)
|
|
499
|
+
(m[1].to_i..m[2].to_i).each {|i| targets << i }
|
|
500
|
+
elsif /\A\d+\z/.match? token
|
|
501
|
+
targets << token.to_i
|
|
502
|
+
end
|
|
503
|
+
end
|
|
504
|
+
targets.empty? ? :all : targets
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
# A single item within a ulist/olist (and a dlist using the
|
|
508
|
+
# unordered/ordered/qanda styles, real ListItem objects
|
|
509
|
+
# asciidoctor-pdf itself synthesizes and routes through here the
|
|
510
|
+
# same way). Reads the innermost enclosing list's own target set
|
|
511
|
+
# off the top of the stack convert_targeted_list maintains, not
|
|
512
|
+
# off list itself: for a dlist's synthesized styles, list here is
|
|
513
|
+
# a brand-new List object asciidoctor-pdf builds on the fly with
|
|
514
|
+
# no attributes of its own, never the real, marked dlist node, so
|
|
515
|
+
# reading list's own attributes directly would never see the
|
|
516
|
+
# mark. The stack is what carries the real target set down
|
|
517
|
+
# correctly regardless of which path produced this call.
|
|
518
|
+
#
|
|
519
|
+
# list.items.index node relies on plain object identity, correct
|
|
520
|
+
# here: asciidoctor-pdf's own convert_list passes each item
|
|
521
|
+
# straight from list.items into this method, no copying.
|
|
522
|
+
#
|
|
523
|
+
# Deliberately not bracket_change_bar: its own change_bar? node
|
|
524
|
+
# gate checks the item's OWN attributes, always false here, the
|
|
525
|
+
# mark lives on the enclosing list, never the item. That gate is
|
|
526
|
+
# exactly right for every other bracket_change_bar caller (the
|
|
527
|
+
# node being bracketed is the node that was actually marked); it
|
|
528
|
+
# would silently swallow every targeted item's bar here, caught
|
|
529
|
+
# directly by real rendering showing no bar at all despite the
|
|
530
|
+
# target set correctly including this item's index. ink_targeted_
|
|
531
|
+
# list_item_change_bar mirrors bracket_change_bar's own shape
|
|
532
|
+
# without that gate, since membership in targets already answers
|
|
533
|
+
# the "should this bar" question on its own.
|
|
534
|
+
def convert_list_item node, list, opts = {}
|
|
535
|
+
targets = @list_change_bar_target_stack&.last
|
|
536
|
+
if (::Set === targets) && (idx = list.items.index node) && (targets.include? idx + 1)
|
|
537
|
+
ink_targeted_list_item_change_bar { super }
|
|
538
|
+
else
|
|
539
|
+
super
|
|
540
|
+
end
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
def ink_targeted_list_item_change_bar
|
|
544
|
+
bar_from = { page: page_number, cursor: cursor } if @change_bar_attr && !scratch?
|
|
545
|
+
result = yield
|
|
546
|
+
ink_change_bar bar_from, { page: page_number, cursor: cursor } if bar_from
|
|
547
|
+
result
|
|
412
548
|
end
|
|
413
549
|
|
|
414
550
|
def convert_rhrev node
|