asciidoctor-pdf 2.3.20 → 2.3.21
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/README.adoc +1 -1
- data/lib/asciidoctor/pdf/converter.rb +77 -33
- data/lib/asciidoctor/pdf/formatted_text/formatter.rb +2 -1
- data/lib/asciidoctor/pdf/index_catalog.rb +69 -13
- data/lib/asciidoctor/pdf/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4250f6c0a0f203fe5e164656467da521bf4741771dd2627030c02a5401c24970
|
4
|
+
data.tar.gz: ef2cdb91e970f26ec2cbbb680d94db21d613aaf3c339492f63bbdb5c30a19337
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a53a41fffe731219da61c25eea7f443dd7cb3b64594e116637f28f2f43173a8d4f43c1b7040cacee56566a3e0bb6be474a6d488275d02094646ea1d48b1fb9a2
|
7
|
+
data.tar.gz: 717af76d4f0f4d958301f099e68ccd3395bc54b5740b2fa47d741fee2bd13aec2d2f48e5443c5d43f64535f23f6b12dc1a00d1c0dd74216a0f95f7ac15845e89
|
data/CHANGELOG.adoc
CHANGED
@@ -5,6 +5,19 @@
|
|
5
5
|
This document provides a high-level view of the changes to the {project-name} by release.
|
6
6
|
For a detailed view of what has changed, refer to the {url-repo}/commits/main[commit history] on GitHub.
|
7
7
|
|
8
|
+
== 2.3.21 (2025-10-08) - @mojavelinux
|
9
|
+
|
10
|
+
Improvements::
|
11
|
+
|
12
|
+
* remove shy hyphens from text in log message when formatted text cannot be parsed (#2599)
|
13
|
+
* clear float box if next block falls outside of flaot group (#2596)
|
14
|
+
* resolve fonts relative to theme dir before GEM_FONTS_DIR if `pdf-fontsdir` not specified (#2349)
|
15
|
+
* add see and see-also associations on index terms to index (#2527)
|
16
|
+
|
17
|
+
=== Details
|
18
|
+
|
19
|
+
{url-repo}/releases/tag/v2.3.21[git tag] | {url-repo}/compare/v2.3.20\...v2.3.21[full diff]
|
20
|
+
|
8
21
|
== 2.3.20 (2025-09-17) - @mojavelinux
|
9
22
|
|
10
23
|
Improvements::
|
data/README.adoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= Asciidoctor PDF: A native PDF converter for AsciiDoc
|
2
2
|
Dan Allen <https://github.com/mojavelinux[@mojavelinux]>; Sarah White <https://github.com/graphitefriction[@graphitefriction]>
|
3
|
-
v2.3.
|
3
|
+
v2.3.21, 2025-10-08
|
4
4
|
// Settings:
|
5
5
|
:experimental:
|
6
6
|
:idprefix:
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'formatted_string'
|
4
3
|
require_relative 'formatted_text'
|
5
4
|
require_relative 'index_catalog'
|
6
5
|
require_relative 'pdfmark'
|
@@ -403,7 +402,7 @@ module Asciidoctor
|
|
403
402
|
@page_bg_image = {}
|
404
403
|
@page_bg_color = resolve_theme_color :page_background_color, 'FFFFFF'
|
405
404
|
# QUESTION: should ThemeLoader handle registering fonts instead?
|
406
|
-
register_fonts theme.font_catalog, ((doc.attr 'pdf-fontsdir')&.sub '{docdir}', (doc.attr 'docdir')) || 'GEM_FONTS_DIR'
|
405
|
+
register_fonts theme.font_catalog, ((doc.attr 'pdf-fontsdir')&.sub '{docdir}', (doc.attr 'docdir')) || (theme.__dir__ == ThemeLoader::ThemesDir ? 'GEM_FONTS_DIR' : %(#{theme.__dir__};GEM_FONTS_DIR))
|
407
406
|
default_kerning theme.base_font_kerning != 'none'
|
408
407
|
@fallback_fonts = Array theme.font_fallbacks
|
409
408
|
@root_font_size = theme.base_font_size
|
@@ -710,6 +709,7 @@ module Asciidoctor
|
|
710
709
|
end
|
711
710
|
|
712
711
|
def convert_index_section node
|
712
|
+
@index.link_associations
|
713
713
|
if ColumnBox === bounds || (columns = @theme.index_columns || 1) < 2
|
714
714
|
convert_index_categories @index.categories, (node.document.attr 'index-pagenum-sequence-style')
|
715
715
|
else
|
@@ -739,41 +739,73 @@ module Asciidoctor
|
|
739
739
|
end
|
740
740
|
|
741
741
|
def convert_index_term term, pagenum_sequence_style = nil
|
742
|
-
|
742
|
+
# NOTE: dup fragment list and all fragments to avoid any modification
|
743
|
+
term_fragments = term.name.fragments.map(&:dup)
|
743
744
|
unless term.container?
|
744
|
-
pagenum_fragment = (parse_text %(<a>#{DummyText}</a>), inline_format: true)[0]
|
745
745
|
if @media == 'screen'
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
pagenums = term.dests.map {|dest| pagenum_fragment.merge text: dest[:page], anchor: dest[:anchor] }
|
746
|
+
link_fragment = (parse_text %(<a>#{DummyText}</a>), inline_format: true)[0]
|
747
|
+
term_fragments.unshift name: term.anchor, callback: [FormattedText::InlineDestinationMarker], text: DummyText
|
748
|
+
end
|
749
|
+
if (see = term.see)
|
750
|
+
term_fragments << { text: ' (see ' }
|
751
|
+
if link_fragment && IndexTerm === see
|
752
|
+
link_fragment_ = link_fragment.merge anchor: see.anchor
|
753
|
+
see.name.fragments.each {|it| term_fragments << (link_fragment_.merge it) }
|
754
|
+
else
|
755
|
+
term_fragments.concat see.name.fragments
|
757
756
|
end
|
757
|
+
term_fragments << { text: ')' }
|
758
758
|
else
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
759
|
+
if @media == 'screen'
|
760
|
+
case pagenum_sequence_style
|
761
|
+
when 'page'
|
762
|
+
pagenums = term.dests.uniq {|dest| dest[:page] }.map {|dest| link_fragment.merge anchor: dest[:anchor], text: dest[:page] }
|
763
|
+
when 'range'
|
764
|
+
first_anchor_per_page = {}.tap {|accum| term.dests.each {|dest| accum[dest[:page]] ||= dest[:anchor] } }
|
765
|
+
pagenums = (consolidate_ranges first_anchor_per_page.keys).map do |range|
|
766
|
+
anchor = first_anchor_per_page[(range.include? '-') ? (range.partition '-')[0] : range]
|
767
|
+
link_fragment.merge text: range, anchor: anchor
|
768
|
+
end
|
769
|
+
else # term
|
770
|
+
pagenums = term.dests.map {|dest| link_fragment.merge text: dest[:page], anchor: dest[:anchor] }
|
771
|
+
end
|
764
772
|
else
|
765
|
-
|
766
|
-
|
773
|
+
pagenums = consolidate_ranges term.dests.map {|dest| dest[:page] }.uniq
|
774
|
+
end
|
775
|
+
pagenums.each do |pagenum|
|
776
|
+
if ::String === pagenum
|
777
|
+
term_fragments << ({ text: %(, #{pagenum}) })
|
778
|
+
else
|
779
|
+
term_fragments << { text: ', ' }
|
780
|
+
term_fragments << pagenum
|
781
|
+
end
|
782
|
+
end
|
783
|
+
if (see_also = term.see_also)
|
784
|
+
see_also_items = []
|
785
|
+
see_also.each do |also_term|
|
786
|
+
see_also_fragments = [{ text: '(see also ' }]
|
787
|
+
if link_fragment && IndexTerm === also_term
|
788
|
+
link_fragment_ = link_fragment.merge anchor: also_term.anchor
|
789
|
+
also_term.name.fragments.map {|it| see_also_fragments << (link_fragment_.merge it) }
|
790
|
+
else
|
791
|
+
see_also_fragments.concat also_term.name.fragments
|
792
|
+
end
|
793
|
+
see_also_fragments << { text: ')' }
|
794
|
+
see_also_items << see_also_fragments
|
795
|
+
end
|
767
796
|
end
|
768
797
|
end
|
769
798
|
end
|
770
799
|
subterm_indent = @theme.description_list_description_indent
|
771
800
|
typeset_formatted_text term_fragments, (calc_line_metrics @base_line_height), align: :left, color: @font_color, hanging_indent: subterm_indent * 2, consolidate: true
|
772
801
|
indent subterm_indent do
|
802
|
+
see_also_items&.each do |see_also_fragments|
|
803
|
+
typeset_formatted_text see_also_fragments, (calc_line_metrics @base_line_height), align: :left, color: @font_color, hanging_indent: subterm_indent * 2, consolidate: true
|
804
|
+
end
|
773
805
|
term.subterms.each do |subterm|
|
774
806
|
convert_index_term subterm, pagenum_sequence_style
|
775
|
-
end
|
776
|
-
end
|
807
|
+
end unless term.leaf?
|
808
|
+
end if see_also_items || !term.leaf?
|
777
809
|
end
|
778
810
|
|
779
811
|
def convert_preamble node
|
@@ -871,14 +903,19 @@ module Asciidoctor
|
|
871
903
|
end
|
872
904
|
|
873
905
|
if (float_box = (@float_box ||= nil))
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
906
|
+
if (prev_sibling = node.previous_sibling)&.context == :open && (prev_sibling.role? 'float-group')
|
907
|
+
move_cursor_to float_box[:bottom]
|
908
|
+
@float_box = nil
|
909
|
+
else
|
910
|
+
ink_paragraph_in_float_box node, float_box, prose_opts, role_keys, block_next, insert_margin_bottom
|
911
|
+
return
|
912
|
+
end
|
881
913
|
end
|
914
|
+
# TODO: check if we're within one line of the bottom of the page
|
915
|
+
# and advance to the next page if so (similar to logic for section titles)
|
916
|
+
ink_caption node, labeled: false if node.title?
|
917
|
+
role_keys ? theme_font_cascade(role_keys) { ink_prose node.content, prose_opts } : (ink_prose node.content, prose_opts)
|
918
|
+
insert_margin_bottom.call
|
882
919
|
end
|
883
920
|
|
884
921
|
def convert_admonition node
|
@@ -2667,12 +2704,19 @@ module Asciidoctor
|
|
2667
2704
|
# NOTE: page number (:page key) is added by InlineDestinationMarker
|
2668
2705
|
dest = { anchor: (anchor_name = @index.next_anchor_name) }
|
2669
2706
|
anchor = %(<a id="#{anchor_name}" type="indexterm"#{visible ? ' visible="true"' : ''}>#{DummyText}</a>)
|
2707
|
+
assoc = {}
|
2708
|
+
if (see = node.attr 'see')
|
2709
|
+
assoc[:see] = parse_text see, inline_format: [normalize: true]
|
2710
|
+
end
|
2711
|
+
if (see_also = node.attr 'see-also')
|
2712
|
+
assoc[:see_also] = see_also.map {|term| parse_text term, inline_format: [normalize: true] }
|
2713
|
+
end
|
2670
2714
|
if visible
|
2671
2715
|
visible_term = node.text
|
2672
|
-
@index.
|
2716
|
+
@index.store_term [(parse_text visible_term, inline_format: [normalize: true])], dest, assoc
|
2673
2717
|
%(#{anchor}#{visible_term})
|
2674
2718
|
else
|
2675
|
-
@index.store_term (node.attr 'terms').map {|term|
|
2719
|
+
@index.store_term (node.attr 'terms').map {|term| parse_text term, inline_format: [normalize: true] }, dest, assoc
|
2676
2720
|
anchor
|
2677
2721
|
end
|
2678
2722
|
end
|
@@ -10,6 +10,7 @@ module Asciidoctor
|
|
10
10
|
|
11
11
|
FormattingSnifferPattern = /[<&]/
|
12
12
|
WHITESPACE = %( \t\n)
|
13
|
+
SHY = ::Prawn::Text::SHY
|
13
14
|
|
14
15
|
def initialize options = {}
|
15
16
|
@parser = MarkupParser.new
|
@@ -26,7 +27,7 @@ module Asciidoctor
|
|
26
27
|
return @transform.apply parsed.content, [], inherited
|
27
28
|
end
|
28
29
|
reason = @parser.failure_reason.sub %r/ at line \d+, column \d+ \(byte (\d+)\)(.*)/, '\2 at byte \1'
|
29
|
-
logger.error %(failed to parse formatted text: #{string} (reason: #{reason})) unless @scratch
|
30
|
+
logger.error %(failed to parse formatted text: #{string.tr SHY, ''} (reason: #{reason.tr SHY, ''})) unless @scratch
|
30
31
|
end
|
31
32
|
[inherited ? (inherited.merge text: string) : { text: string }]
|
32
33
|
end
|
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'digest'
|
4
|
+
require_relative 'formatted_string'
|
5
|
+
|
3
6
|
module Asciidoctor
|
4
7
|
module PDF
|
5
8
|
class IndexCatalog
|
@@ -20,29 +23,29 @@ module Asciidoctor
|
|
20
23
|
%(__indexterm-#{@sequence += 1})
|
21
24
|
end
|
22
25
|
|
23
|
-
def store_term names, dest
|
24
|
-
if (num_terms = names.size)
|
25
|
-
|
26
|
+
def store_term names, dest, assoc = {}
|
27
|
+
if (num_terms = (names = names.map {|name| FormattedString.new name }).size) == 1
|
28
|
+
store_primary_term names[0], dest, assoc
|
26
29
|
elsif num_terms == 2
|
27
|
-
store_secondary_term names[0], names[1], dest
|
28
|
-
elsif num_terms
|
29
|
-
|
30
|
+
store_secondary_term names[0], names[1], dest, assoc
|
31
|
+
elsif num_terms > 2
|
32
|
+
store_tertiary_term names[0], names[1], names[2], dest, assoc
|
30
33
|
end
|
31
34
|
end
|
32
35
|
|
33
|
-
def store_primary_term name, dest = nil
|
36
|
+
def store_primary_term name, dest = nil, assoc = {}
|
34
37
|
store_dest dest if dest
|
35
|
-
(init_category name.chr.upcase).store_term name, dest
|
38
|
+
(init_category name.chr.upcase).store_term name, dest, assoc
|
36
39
|
end
|
37
40
|
|
38
|
-
def store_secondary_term primary_name, secondary_name, dest = nil
|
41
|
+
def store_secondary_term primary_name, secondary_name, dest = nil, assoc = {}
|
39
42
|
store_dest dest if dest
|
40
|
-
(store_primary_term primary_name).store_term secondary_name, dest
|
43
|
+
(store_primary_term primary_name).store_term secondary_name, dest, assoc
|
41
44
|
end
|
42
45
|
|
43
|
-
def store_tertiary_term primary_name, secondary_name, tertiary_name, dest
|
46
|
+
def store_tertiary_term primary_name, secondary_name, tertiary_name, dest, assoc = {}
|
44
47
|
store_dest dest
|
45
|
-
(store_secondary_term primary_name, secondary_name).store_term tertiary_name, dest
|
48
|
+
(store_secondary_term primary_name, secondary_name).store_term tertiary_name, dest, assoc
|
46
49
|
end
|
47
50
|
|
48
51
|
def init_category name
|
@@ -54,6 +57,34 @@ module Asciidoctor
|
|
54
57
|
@categories[name]
|
55
58
|
end
|
56
59
|
|
60
|
+
def find_primary_term name
|
61
|
+
@categories.each_value do |category|
|
62
|
+
term = category.terms.find {|candidate| candidate.name == name }
|
63
|
+
return term if term
|
64
|
+
end
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def link_associations group = nil
|
69
|
+
if group
|
70
|
+
group.terms.each do |term|
|
71
|
+
associations = term.associations
|
72
|
+
if (see_name = associations[:see])
|
73
|
+
see_name = FormattedString.new see_name
|
74
|
+
term.see = (find_primary_term see_name) || (UnresolvedIndexTerm.new see_name)
|
75
|
+
elsif (see_also_names = associations[:see_also])
|
76
|
+
term.see_also = see_also_names.map do |see_also_name|
|
77
|
+
see_also_name = FormattedString.new see_also_name
|
78
|
+
(find_primary_term see_also_name) || (UnresolvedIndexTerm.new see_also_name)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
link_associations term unless term.leaf?
|
82
|
+
end
|
83
|
+
else
|
84
|
+
@categories.each_value {|category| link_associations category }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
57
88
|
def store_dest dest
|
58
89
|
@dests[dest[:anchor]] = dest
|
59
90
|
end
|
@@ -83,9 +114,18 @@ module Asciidoctor
|
|
83
114
|
@terms = {}
|
84
115
|
end
|
85
116
|
|
86
|
-
def store_term name, dest
|
117
|
+
def store_term name, dest, assoc = {}
|
87
118
|
term = (@terms[name] ||= (IndexTerm.new name))
|
88
119
|
term.add_dest dest if dest
|
120
|
+
term.associations ||= {}
|
121
|
+
unless assoc.empty?
|
122
|
+
if !term.associations[:see] && (see = assoc[:see])
|
123
|
+
term.associations[:see] = see
|
124
|
+
end
|
125
|
+
if (see_also = assoc[:see_also])
|
126
|
+
(term.associations[:see_also] ||= []).concat see_also
|
127
|
+
end
|
128
|
+
end
|
89
129
|
term
|
90
130
|
end
|
91
131
|
|
@@ -100,10 +140,22 @@ module Asciidoctor
|
|
100
140
|
|
101
141
|
class IndexTermCategory < IndexTermGroup; end
|
102
142
|
|
143
|
+
class UnresolvedIndexTerm < IndexTermGroup; end
|
144
|
+
|
103
145
|
class IndexTerm < IndexTermGroup
|
146
|
+
attr_reader :anchor
|
147
|
+
|
148
|
+
attr_accessor :associations
|
149
|
+
|
150
|
+
attr_accessor :see
|
151
|
+
|
152
|
+
attr_writer :see_also
|
153
|
+
|
104
154
|
def initialize name
|
105
155
|
super
|
106
156
|
@dests = ::Set.new
|
157
|
+
@anchor = %(__indextermdef-#{(::Digest::MD5.new << name.to_s).hexdigest})
|
158
|
+
@associations = @see = @see_also = nil
|
107
159
|
end
|
108
160
|
|
109
161
|
alias subterms terms
|
@@ -124,6 +176,10 @@ module Asciidoctor
|
|
124
176
|
def leaf?
|
125
177
|
@terms.empty?
|
126
178
|
end
|
179
|
+
|
180
|
+
def see_also
|
181
|
+
@see_also&.sort
|
182
|
+
end
|
127
183
|
end
|
128
184
|
end
|
129
185
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: asciidoctor-pdf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.3.
|
4
|
+
version: 2.3.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Allen
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2025-
|
12
|
+
date: 2025-10-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: asciidoctor
|