asciidoctor-rhrev 1.2.3 → 1.3.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: 87f9419e740ba6f0002e1a4fd06c2930319910ff2a3bf2fbeeefbfee33d6c0d3
4
- data.tar.gz: 2c6759b77bd7c9ab7d16e906a569541c36a185a594f45b0e398e2f028087e0bc
3
+ metadata.gz: b64bf51f30ba6f298ac05c96c68df9b5a1d42c1c0671ca2cedf903df53b2c584
4
+ data.tar.gz: 359c71a434b72fa4cb734362c27eae1a499ad96480602ab1ae9d1e1d73f69789
5
5
  SHA512:
6
- metadata.gz: d939d3d0be086e54ef94165c96532594992d45adf7d3f93cd1b1d64b2667db5bddfdfc6566252b7dc0b830536c46c2dc822c313d19477ec78c0e8dfbb816905a
7
- data.tar.gz: 9918859a0819b3ad98926199f499eab62ff3185cd012f31b0c45fe5b8f76ae310c6fcdb9ab3096fa256335b2d5cdd42fb1f1a739e6cbba53e8db9da5c3fbb654
6
+ metadata.gz: 7380f1500ae2ba4befc6b3650cbc02fb2f5db15588fedfca99fc59ec17ae6dff557225f470a71908fd2af7c06d5217e55f1bee1e9f4eb1fcc1042f68657b6a94
7
+ data.tar.gz: 612871f81c20e144fbda5901cebf46a122005786d719dab0a2557bf04a609e508ff7238c69794e62ea46dcde8761b7d26dca694427d3e8d5f01d7a630c49e241
data/CHANGELOG.adoc CHANGED
@@ -1,5 +1,17 @@
1
1
  = Changelog
2
2
 
3
+ == 1.3.1 (2026-07-28)
4
+
5
+ * Fix silent content loss in long revision-history tables (PDF backend): the extent dry-run that reserves space for the table now runs after `prescan_document` populates each tracked node's real `title`/`sectnum`/`reftext`/`caption_number`, so a description cross-reference (`[.rhrevdescription]`) that forward-references its own target no longer measures a humanized-anchor placeholder in the dry-run and the resolved text in the final backfill. When the two lengths differed, the accumulated row heights could shift a row across a reserved page boundary and drop its content from the output; measurement and backfill now agree. The metadata pass is gated on nodes carrying their own `rhrevN-M` attribute, so it adds no full-document walk
6
+ * Fix the `rhrev-table-extra-blank-row` trailing blank row overflowing alone onto a continuation page (PDF backend): when the real entries nearly fill a page, the trailing blank row is now dropped rather than paginated to a page of its own. The check is scoped to the revision-history table's own last row and decided once per row, so no other table's pagination is affected and a multi-column blank row is never half-drawn
7
+ * Note: this is a PDF-only release; the npm package skips 1.3.1
8
+
9
+ == 1.3.0 (2026-07-16)
10
+
11
+ * Add HTML change bars: with `:rhrev-change-bars:` set, tracked blocks (section, floating title, example, listing, table, image) marked with the current revision get the `rhrev-changed` CSS class in the HTML backend and the Antora extension; `rhrev-change-bars-color`, `-width`, and `-offset` are emitted as CSS custom properties (`--rhrev-change-bar-*`). The side is always right in HTML (no recto/verso model), and a marked section's bar spans its nested subsections, unlike the PDF backend. Default styling (red right border) ships in the baiyibai UI bundle
12
+ * Fix the documented Assembler xref format example emitting a "possible invalid reference" warning by escaping the inline example
13
+ * Replace the figure example in the docs with an original image (gem and npm both 1.3.0)
14
+
3
15
  == 1.2.3 (2026-07-15)
4
16
 
5
17
  * Fix the initial-release table (revnumber `1.0`/`1` with `rhrev-initial-handling` `initial-release`) rendering a "Major changes since Revision X" header row: an initial release has no prior revision, so the table is now a single `Page | Initial Release` row (PDF backend, HTML backend, and Antora extension). Caption, custom first row, and all localization/customization attributes are unaffected; `rhrev-localization-major-changes` still applies to the regular revision-history table
@@ -279,6 +279,17 @@ module Asciidoctor
279
279
  end
280
280
  end
281
281
 
282
+ # True when the node carries its own rhrev* attribute in its raw (non-inherited)
283
+ # attribute set -- the same check collect_revision_entries makes, hoisted out so
284
+ # prescan_document can gate update_revision_entry_metadata on it.
285
+ def node_carries_own_rhrev? node
286
+ return false unless node.respond_to?(:attributes)
287
+ raw = (node.instance_variable_get(:@attributes) rescue nil)
288
+ return false if raw.nil? || raw.empty?
289
+ prefix = @revision_prefix || 'rhrev'
290
+ raw.keys.any? { |k| k.to_s.start_with?(prefix) }
291
+ end
292
+
282
293
  def update_revision_entry_metadata node
283
294
  return unless node.id
284
295
  return unless node.respond_to?(:attributes)
@@ -459,6 +470,13 @@ module Asciidoctor
459
470
  [:section, :floating_title, :example, :listing, :table, :image].each do |ctx|
460
471
  doc.find_by(context: ctx).each do |node|
461
472
  collect_revision_entries node
473
+ # Populate the *real* title/sectnum/reftext/caption_number now, from
474
+ # the parsed AST, so the extent dry-run measures the same content the
475
+ # deferred backfill will later ink. Gated on the node carrying its own
476
+ # rhrevN-M attribute: reusing node.attributes here (inherited config keys
477
+ # like rhrev-table-caption match the prefix) would turn this into a full
478
+ # per-node document walk.
479
+ update_revision_entry_metadata node if node_carries_own_rhrev? node
462
480
  end
463
481
  end
464
482
 
@@ -329,15 +329,24 @@ module Asciidoctor
329
329
 
330
330
  def create_revision_table_properly doc
331
331
  asciidoc_table = build_table_via_parsing doc
332
-
332
+
333
333
  disable_caption = doc.attr? 'rhrev-disable-caption'
334
334
  if disable_caption
335
335
  saved_caption = doc.attr 'table-caption'
336
336
  doc.set_attr 'table-caption', ''
337
337
  end
338
-
339
- convert_table asciidoc_table
340
-
338
+
339
+ # Scope the lonely-trailing-blank-row skip (PrawnTableDrawPatch) to just
340
+ # this table. Both the extent dry-run and the real ink flow through here,
341
+ # so the skip is applied identically in measurement and draw.
342
+ had_skip_flag = @_rhrev_skip_lonely_blank_row
343
+ @_rhrev_skip_lonely_blank_row = true if doc.attr? 'rhrev-table-extra-blank-row'
344
+ begin
345
+ convert_table asciidoc_table
346
+ ensure
347
+ @_rhrev_skip_lonely_blank_row = had_skip_flag
348
+ end
349
+
341
350
  if disable_caption
342
351
  if saved_caption
343
352
  doc.set_attr 'table-caption', saved_caption
@@ -5,6 +5,49 @@ require 'asciidoctor/converter/html5'
5
5
 
6
6
  module Asciidoctor
7
7
  module Rhrev
8
+ # Tags blocks marked with the current revision (revnumber 1.2 => attribute
9
+ # rhrev1-2) with the rhrev-changed role so a stylesheet can draw an HTML
10
+ # change bar (border on the right side). Enabled by the rhrev-change-bars
11
+ # document attribute, mirroring the PDF backend. The rhrev-change-bars-color,
12
+ # -width, and -offset attributes are emitted as CSS custom properties; the
13
+ # side is always right in HTML output (no recto/verso model).
14
+ class ChangeBarsHtmlTreeprocessor < Asciidoctor::Extensions::Treeprocessor
15
+ TRACKED_CONTEXTS = [:section, :floating_title, :example, :listing, :table, :image].freeze
16
+
17
+ def process document
18
+ return document unless document.basebackend? 'html'
19
+ return document unless document.attr? 'rhrev-change-bars'
20
+ return document unless (revnumber = document.attr 'revnumber')
21
+ prefix = document.attr 'revhistoryprefix', 'rhrev'
22
+ change_attr = %(#{prefix}#{revnumber.to_s.tr '.', '-'})
23
+
24
+ tagged = false
25
+ document.find_by { |b| TRACKED_CONTEXTS.include? b.context }.each do |block|
26
+ next unless block.attributes && (block.attributes.key? change_attr)
27
+ roles = (block.attr 'role')
28
+ block.set_attr 'role', [roles, 'rhrev-changed'].compact.join(' ')
29
+ tagged = true
30
+ end
31
+ return document unless tagged
32
+
33
+ overrides = []
34
+ if (color = document.attr 'rhrev-change-bars-color')
35
+ overrides << %(--rhrev-change-bar-color: ##{color.to_s.delete_prefix '#'};)
36
+ end
37
+ if (width = document.attr 'rhrev-change-bars-width')
38
+ overrides << %(--rhrev-change-bar-width: #{width}px;)
39
+ end
40
+ if (offset = document.attr 'rhrev-change-bars-offset')
41
+ overrides << %(--rhrev-change-bar-offset: #{offset}px;)
42
+ end
43
+ unless overrides.empty?
44
+ style = create_block document, :pass, %(<style>:root { #{overrides.join ' '} }</style>), {}
45
+ document.blocks.unshift style
46
+ end
47
+ document
48
+ end
49
+ end
50
+
8
51
  # Treeprocessor to auto-inject revision history at document start
9
52
  class HtmlTreeprocessor < Asciidoctor::Extensions::Treeprocessor
10
53
  def process document
@@ -5,3 +5,4 @@ require 'asciidoctor/pdf' unless defined? Asciidoctor::PDF
5
5
  require_relative 'converter'
6
6
  require_relative 'renderer'
7
7
  require_relative 'exporter'
8
+ require_relative 'table_draw_patch'
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Scoped override of prawn-table's Table#draw.
4
+ #
5
+ # When the rhrev revision-history table is drawn with rhrev-table-extra-blank-row
6
+ # set, build_table_via_parsing appends a trailing blank (NBSP) row. prawn-table
7
+ # treats that row like any other: if the real entries nearly fill a page, the blank
8
+ # row alone overflows onto a fresh continuation page whose only content is the
9
+ # "(continued)" caption and an invisible row.
10
+ #
11
+ # This patch is INERT for every table except the rhrev revision-history one: draw
12
+ # returns super unless the converter has set @_rhrev_skip_lonely_blank_row on the
13
+ # document around that table's conversion. Only then do we reimplement the 0.2.2 draw
14
+ # loop (verified against prawn-table 0.2.2) with a single added rule: if the table's
15
+ # last row would land alone at the top of a fresh page, drop it instead of paginating
16
+ # to it. The decision is made once, from the row's first cell, and applied to every
17
+ # cell of the row -- prawn-table evaluates pagination per cell, so re-deciding per cell
18
+ # could ink one cell of the row and drop the other, leaving a half-drawn blank row.
19
+
20
+ begin
21
+ require 'prawn/table' unless defined? ::Prawn::Table
22
+ rescue LoadError
23
+ # prawn-table not present; nothing to patch
24
+ end
25
+
26
+ if defined? ::Prawn::Table
27
+ module Asciidoctor
28
+ module PDF
29
+ module Rhrev
30
+ module PrawnTableDrawPatch
31
+ def draw
32
+ unless @pdf.respond_to?(:instance_variable_get) &&
33
+ @pdf.instance_variable_get(:@_rhrev_skip_lonely_blank_row)
34
+ return super
35
+ end
36
+
37
+ # Defensive: only take the reimplemented path when the prawn-table
38
+ # internals we rely on are exactly the shape we reimplement against
39
+ # (0.2.2). On any drift, fall back to stock behavior.
40
+ internals = %i[initial_row_on_initial_page start_new_page?
41
+ ink_and_draw_cells_and_start_new_page set_background_color
42
+ ink_and_draw_cells header_rows with_position]
43
+ unless internals.all? { |m| respond_to?(m, true) } &&
44
+ @pdf.respond_to?(:reference_bounds)
45
+ return super
46
+ end
47
+
48
+ with_position do
49
+ ref_bounds = @pdf.reference_bounds
50
+ started_new_page_at_row = initial_row_on_initial_page
51
+ offset = @pdf.y
52
+ @header_row = header_rows if @header
53
+
54
+ cells_this_page = []
55
+ last_drawn_cell = nil
56
+
57
+ last_row_index = @cells.map(&:row).max
58
+ blank_row_decided = false
59
+ skip_blank_row = false
60
+
61
+ @cells.each do |cell|
62
+ if cell.row == last_row_index && rhrev_blank_cell?(cell)
63
+ # Decide once, from the first (column 0) cell of the last row, and
64
+ # apply the same answer to every cell of that row.
65
+ unless blank_row_decided
66
+ skip_blank_row = start_new_page?(cell, offset, ref_bounds)
67
+ blank_row_decided = true
68
+ end
69
+ next if skip_blank_row
70
+ end
71
+
72
+ if start_new_page?(cell, offset, ref_bounds)
73
+ cells_this_page, offset = ink_and_draw_cells_and_start_new_page(cells_this_page, cell)
74
+ started_new_page_at_row = cell.row
75
+ end
76
+
77
+ cell = set_background_color(cell, started_new_page_at_row)
78
+ cells_this_page << [cell, [cell.relative_x, cell.relative_y(offset)]]
79
+ last_drawn_cell = cell
80
+ end
81
+
82
+ ink_and_draw_cells(cells_this_page)
83
+
84
+ # @cells.last may now be a dropped blank cell; anchor the final cursor
85
+ # to the last cell we actually inked.
86
+ if last_drawn_cell
87
+ @pdf.move_cursor_to(last_drawn_cell.relative_y(offset) - last_drawn_cell.height)
88
+ end
89
+ end
90
+ end
91
+
92
+ # The trailing row appended for rhrev-table-extra-blank-row is a pair of
93
+ # non-breaking-space cells. Treat a last-row cell as blank when its content
94
+ # is empty once NBSP/whitespace is stripped; when the content can't be read,
95
+ # rely on the caller's flag + last-row guarantee and treat it as blank.
96
+ def rhrev_blank_cell? cell
97
+ content = (cell.content.to_s rescue nil)
98
+ return true if content.nil?
99
+ content.gsub(/[ \s]|&#160;|&nbsp;/, '').empty?
100
+ end
101
+ end
102
+
103
+ ::Prawn::Table.prepend PrawnTableDrawPatch
104
+ end
105
+ end
106
+ end
107
+ end
@@ -31,4 +31,5 @@ Asciidoctor::Extensions.register do
31
31
  block_macro Asciidoctor::Rhrev::RhrevBlockMacroProcessor
32
32
  inline_macro Asciidoctor::Rhrev::PagerhrefInlineMacroProcessor
33
33
  treeprocessor Asciidoctor::Rhrev::HtmlTreeprocessor if html_available
34
+ treeprocessor Asciidoctor::Rhrev::ChangeBarsHtmlTreeprocessor if html_available
34
35
  end
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.2.3
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - 白一百 baiyibai
@@ -46,6 +46,7 @@ files:
46
46
  - lib/asciidoctor/rhrev/renderer.rb
47
47
  - lib/asciidoctor/rhrev/rhrev_html.rb
48
48
  - lib/asciidoctor/rhrev/rhrev_pdf.rb
49
+ - lib/asciidoctor/rhrev/table_draw_patch.rb
49
50
  homepage: https://gitlab.com/baiyibai/rhrev-asciidoctor-automatic-revision-history
50
51
  licenses:
51
52
  - CC0-1.0