asciidoctor-pdf 1.5.0.beta.8 → 1.5.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +49 -0
  3. data/LICENSE.adoc +1 -1
  4. data/NOTICE.adoc +1 -1
  5. data/README.adoc +43 -47
  6. data/asciidoctor-pdf.gemspec +5 -1
  7. data/bin/asciidoctor-pdf-optimize +1 -1
  8. data/data/themes/base-theme.yml +4 -3
  9. data/data/themes/default-theme.yml +10 -5
  10. data/docs/theming-guide.adoc +286 -22
  11. data/lib/asciidoctor-pdf.rb +1 -0
  12. data/lib/asciidoctor-pdf/converter.rb +1 -0
  13. data/lib/asciidoctor-pdf/version.rb +1 -0
  14. data/lib/asciidoctor/pdf.rb +13 -2
  15. data/lib/asciidoctor/pdf/converter.rb +3962 -3955
  16. data/lib/asciidoctor/pdf/ext.rb +9 -0
  17. data/lib/asciidoctor/pdf/ext/asciidoctor.rb +1 -0
  18. data/lib/asciidoctor/pdf/ext/asciidoctor/abstract_block.rb +1 -0
  19. data/lib/asciidoctor/pdf/ext/asciidoctor/abstract_node.rb +1 -0
  20. data/lib/asciidoctor/pdf/ext/asciidoctor/document.rb +1 -0
  21. data/lib/asciidoctor/pdf/ext/asciidoctor/image.rb +18 -16
  22. data/lib/asciidoctor/pdf/ext/asciidoctor/list.rb +3 -2
  23. data/lib/asciidoctor/pdf/ext/asciidoctor/list_item.rb +2 -1
  24. data/lib/asciidoctor/pdf/ext/asciidoctor/logging_shim.rb +3 -4
  25. data/lib/asciidoctor/pdf/ext/asciidoctor/section.rb +8 -6
  26. data/lib/asciidoctor/pdf/ext/core.rb +2 -0
  27. data/lib/asciidoctor/pdf/ext/core/array.rb +1 -0
  28. data/lib/asciidoctor/pdf/ext/core/hash.rb +1 -0
  29. data/lib/asciidoctor/pdf/ext/core/numeric.rb +4 -3
  30. data/lib/asciidoctor/pdf/ext/core/object.rb +1 -0
  31. data/lib/asciidoctor/pdf/ext/core/quantifiable_stdout.rb +8 -1
  32. data/lib/asciidoctor/pdf/ext/core/regexp.rb +1 -0
  33. data/lib/asciidoctor/pdf/ext/core/string.rb +6 -7
  34. data/lib/asciidoctor/pdf/ext/pdf-core.rb +1 -0
  35. data/lib/asciidoctor/pdf/ext/pdf-core/page.rb +3 -4
  36. data/lib/asciidoctor/pdf/ext/pdf-core/pdf_object.rb +2 -1
  37. data/lib/asciidoctor/pdf/ext/prawn-svg.rb +1 -0
  38. data/lib/asciidoctor/pdf/ext/prawn-svg/interface.rb +11 -8
  39. data/lib/asciidoctor/pdf/ext/prawn-table.rb +2 -1
  40. data/lib/asciidoctor/pdf/ext/prawn-table/cell.rb +9 -10
  41. data/lib/asciidoctor/pdf/ext/prawn-table/cell/asciidoc.rb +62 -57
  42. data/lib/asciidoctor/pdf/ext/prawn-table/cell/text.rb +5 -3
  43. data/lib/asciidoctor/pdf/ext/prawn-templates.rb +1 -0
  44. data/lib/asciidoctor/pdf/ext/prawn.rb +1 -0
  45. data/lib/asciidoctor/pdf/ext/prawn/coderay_encoder.rb +73 -72
  46. data/lib/asciidoctor/pdf/ext/prawn/extensions.rb +814 -818
  47. data/lib/asciidoctor/pdf/ext/prawn/font/afm.rb +4 -3
  48. data/lib/asciidoctor/pdf/ext/prawn/formatted_text/box.rb +2 -1
  49. data/lib/asciidoctor/pdf/ext/prawn/formatted_text/fragment.rb +7 -2
  50. data/lib/asciidoctor/pdf/ext/prawn/images.rb +45 -44
  51. data/lib/asciidoctor/pdf/ext/pygments.rb +34 -0
  52. data/lib/asciidoctor/pdf/ext/rouge.rb +1 -1
  53. data/lib/asciidoctor/pdf/ext/rouge/formatters/prawn.rb +181 -149
  54. data/lib/asciidoctor/pdf/ext/rouge/themes/asciidoctor_pdf_default.rb +1 -0
  55. data/lib/asciidoctor/pdf/formatted_text.rb +2 -0
  56. data/lib/asciidoctor/pdf/formatted_text/formatter.rb +35 -34
  57. data/lib/asciidoctor/pdf/formatted_text/fragment_position_renderer.rb +8 -7
  58. data/lib/asciidoctor/pdf/formatted_text/inline_destination_marker.rb +13 -14
  59. data/lib/asciidoctor/pdf/formatted_text/inline_image_arranger.rb +112 -133
  60. data/lib/asciidoctor/pdf/formatted_text/inline_image_renderer.rb +43 -41
  61. data/lib/asciidoctor/pdf/formatted_text/inline_text_aligner.rb +15 -14
  62. data/lib/asciidoctor/pdf/formatted_text/source_wrap.rb +43 -0
  63. data/lib/asciidoctor/pdf/formatted_text/text_background_and_border_renderer.rb +46 -37
  64. data/lib/asciidoctor/pdf/formatted_text/transform.rb +371 -352
  65. data/lib/asciidoctor/pdf/index_catalog.rb +99 -95
  66. data/lib/asciidoctor/pdf/measurements.rb +51 -48
  67. data/lib/asciidoctor/pdf/optimizer.rb +34 -31
  68. data/lib/asciidoctor/pdf/pdfmark.rb +34 -33
  69. data/lib/asciidoctor/pdf/roman_numeral.rb +80 -79
  70. data/lib/asciidoctor/pdf/sanitizer.rb +38 -37
  71. data/lib/asciidoctor/pdf/temporary_path.rb +10 -9
  72. data/lib/asciidoctor/pdf/text_transformer.rb +101 -100
  73. data/lib/asciidoctor/pdf/theme_loader.rb +258 -256
  74. data/lib/asciidoctor/pdf/version.rb +5 -4
  75. metadata +55 -6
  76. data/lib/asciidoctor/pdf/ext/rouge/themes/bw.rb +0 -39
  77. data/lib/asciidoctor/pdf/ext/ttfunk.rb +0 -9
@@ -1,129 +1,133 @@
1
1
  # frozen_string_literal: true
2
- module Asciidoctor; module PDF
3
- class IndexCatalog
4
- include ::Asciidoctor::PDF::TextTransformer
5
2
 
6
- LeadingAlphaRx = /^\p{Alpha}/
3
+ module Asciidoctor
4
+ module PDF
5
+ class IndexCatalog
6
+ include ::Asciidoctor::PDF::TextTransformer
7
7
 
8
- attr_accessor :start_page_number
8
+ LeadingAlphaRx = /^\p{Alpha}/
9
9
 
10
- def initialize
11
- @categories = {}
12
- @start_page_number = 1
13
- @dests = {}
14
- @sequence = 0
15
- end
10
+ attr_accessor :start_page_number
16
11
 
17
- def next_anchor_name
18
- %(__indexterm-#{@sequence += 1})
19
- end
12
+ def initialize
13
+ @categories = {}
14
+ @start_page_number = 1
15
+ @dests = {}
16
+ @sequence = 0
17
+ end
20
18
 
21
- def store_term names, dest = nil
22
- if (num_terms = names.size) > 2
23
- store_tertiary_term names[0], names[1], names[2], dest
24
- elsif num_terms == 2
25
- store_secondary_term names[0], names[1], dest
26
- elsif num_terms == 1
27
- store_primary_term names[0], dest
19
+ def next_anchor_name
20
+ %(__indexterm-#{@sequence += 1})
28
21
  end
29
- end
30
22
 
31
- def store_primary_term name, dest = nil
32
- store_dest dest if dest
33
- (init_category uppercase_mb name.chr).store_term name, dest
34
- end
23
+ def store_term names, dest = nil
24
+ if (num_terms = names.size) > 2
25
+ store_tertiary_term names[0], names[1], names[2], dest
26
+ elsif num_terms == 2
27
+ store_secondary_term names[0], names[1], dest
28
+ elsif num_terms == 1
29
+ store_primary_term names[0], dest
30
+ end
31
+ end
35
32
 
36
- def store_secondary_term primary_name, secondary_name, dest = nil
37
- store_dest dest if dest
38
- (store_primary_term primary_name).store_term secondary_name, dest
39
- end
33
+ def store_primary_term name, dest = nil
34
+ store_dest dest if dest
35
+ (init_category uppercase_mb name.chr).store_term name, dest
36
+ end
40
37
 
41
- def store_tertiary_term primary_name, secondary_name, tertiary_name, dest = nil
42
- store_dest dest if dest
43
- (store_secondary_term primary_name, secondary_name).store_term tertiary_name, dest
44
- end
38
+ def store_secondary_term primary_name, secondary_name, dest = nil
39
+ store_dest dest if dest
40
+ (store_primary_term primary_name).store_term secondary_name, dest
41
+ end
45
42
 
46
- def init_category name
47
- name = '@' unless LeadingAlphaRx.match? name
48
- @categories[name] ||= IndexTermCategory.new name
49
- end
43
+ def store_tertiary_term primary_name, secondary_name, tertiary_name, dest = nil
44
+ store_dest dest if dest
45
+ (store_secondary_term primary_name, secondary_name).store_term tertiary_name, dest
46
+ end
50
47
 
51
- def find_category name
52
- @categories[name]
53
- end
48
+ def init_category name
49
+ name = '@' unless LeadingAlphaRx.match? name
50
+ @categories[name] ||= IndexTermCategory.new name
51
+ end
54
52
 
55
- def store_dest dest
56
- @dests[dest[:anchor]] = dest
57
- end
53
+ def find_category name
54
+ @categories[name]
55
+ end
58
56
 
59
- def link_dest_to_page anchor, physical_page_number
60
- if (dest = @dests[anchor])
61
- dest[:page] = physical_page_number - (@start_page_number - 1)
57
+ def store_dest dest
58
+ @dests[dest[:anchor]] = dest
62
59
  end
63
- end
64
60
 
65
- def empty?
66
- @categories.empty?
67
- end
61
+ def link_dest_to_page anchor, physical_page_number
62
+ if (dest = @dests[anchor])
63
+ virtual_page_number = physical_page_number - (@start_page_number - 1)
64
+ dest[:page] = (virtual_page_number < 1 ? (RomanNumeral.new physical_page_number, :lower) : virtual_page_number).to_s
65
+ end
66
+ end
67
+
68
+ def empty?
69
+ @categories.empty?
70
+ end
68
71
 
69
- def categories
70
- @categories.empty? ? [] : @categories.values.sort
72
+ def categories
73
+ @categories.empty? ? [] : @categories.values.sort
74
+ end
71
75
  end
72
- end
73
76
 
74
- class IndexTermGroup
75
- include Comparable
76
- attr_reader :name
77
+ class IndexTermGroup
78
+ include Comparable
79
+ attr_reader :name
77
80
 
78
- def initialize name
79
- @name = name
80
- @terms = {}
81
- end
81
+ def initialize name
82
+ @name = name
83
+ @terms = {}
84
+ end
82
85
 
83
- def store_term name, dest = nil
84
- term = (@terms[name] ||= (IndexTerm.new name))
85
- term.add_dest dest if dest
86
- term
87
- end
86
+ def store_term name, dest = nil
87
+ term = (@terms[name] ||= (IndexTerm.new name))
88
+ term.add_dest dest if dest
89
+ term
90
+ end
88
91
 
89
- def find_term name
90
- @terms[name]
91
- end
92
+ def find_term name
93
+ @terms[name]
94
+ end
92
95
 
93
- def terms
94
- @terms.empty? ? [] : @terms.values.sort
95
- end
96
+ def terms
97
+ @terms.empty? ? [] : @terms.values.sort
98
+ end
96
99
 
97
- def <=> other
98
- @name <=> other.name
100
+ def <=> other
101
+ (val = @name.casecmp other.name) == 0 ? @name <=> other.name : val
102
+ end
99
103
  end
100
- end
101
104
 
102
- class IndexTermCategory < IndexTermGroup; end
105
+ class IndexTermCategory < IndexTermGroup; end
103
106
 
104
- class IndexTerm < IndexTermGroup
105
- def initialize name
106
- super
107
- @dests = ::Set.new
108
- end
107
+ class IndexTerm < IndexTermGroup
108
+ def initialize name
109
+ super
110
+ @dests = ::Set.new
111
+ end
109
112
 
110
- alias subterms terms
113
+ alias subterms terms
111
114
 
112
- def add_dest dest
113
- @dests << dest
114
- self
115
- end
115
+ def add_dest dest
116
+ @dests << dest
117
+ self
118
+ end
116
119
 
117
- def dests
118
- @dests.select {|d| d.key? :page }.sort {|a, b| a[:page] <=> b[:page] }
119
- end
120
+ def dests
121
+ @dests.select {|d| d.key? :page }.sort {|a, b| a[:page] <=> b[:page] }
122
+ end
120
123
 
121
- def container?
122
- @dests.empty? || @dests.none? {|d| d.key? :page }
123
- end
124
+ def container?
125
+ @dests.empty? || @dests.none? {|d| d.key? :page }
126
+ end
124
127
 
125
- def leaf?
126
- @terms.empty?
128
+ def leaf?
129
+ @terms.empty?
130
+ end
127
131
  end
128
132
  end
129
- end; end
133
+ end
@@ -1,59 +1,62 @@
1
1
  # frozen_string_literal: true
2
- module Asciidoctor; module PDF
3
- module Measurements
4
- MeasurementValueRx = /(\d+|\d*\.\d+)(in|mm|cm|p[txc])?$/
5
- InsetMeasurementValueRx = /(?<=^| |\()(-?\d+(?:\.\d+)?)(in|mm|cm|p[txc])(?=$| |\))/
6
- MeasurementValueHintRx = /\d(in|mm|cm|p[txc])/
7
2
 
8
- # Convert the specified string value to a pt value from the
9
- # specified unit of measurement (e.g., in, cm, mm, etc).
10
- # If the unit of measurement is not recognized, assume pt.
11
- #
12
- # Examples:
13
- #
14
- # 0.5in => 36.0
15
- # 100px => 75.0
16
- # 72blah => 72.0
17
- #
18
- def str_to_pt val
19
- MeasurementValueRx =~ val ? (to_pt $1.to_f, $2) : val.to_f
20
- end
3
+ module Asciidoctor
4
+ module PDF
5
+ module Measurements
6
+ MeasurementValueRx = /(\d+|\d*\.\d+)(in|mm|cm|p[txc])?$/
7
+ InsetMeasurementValueRx = /(?<=^| |\()(-?\d+(?:\.\d+)?)(in|mm|cm|p[txc])(?=$| |\))/
8
+ MeasurementValueHintRx = /\d(in|mm|cm|p[txc])/
9
+
10
+ # Convert the specified string value to a pt value from the
11
+ # specified unit of measurement (e.g., in, cm, mm, etc).
12
+ # If the unit of measurement is not recognized, assume pt.
13
+ #
14
+ # Examples:
15
+ #
16
+ # 0.5in => 36.0
17
+ # 100px => 75.0
18
+ # 72blah => 72.0
19
+ #
20
+ def str_to_pt val
21
+ MeasurementValueRx =~ val ? (to_pt $1.to_f, $2) : val.to_f
22
+ end
21
23
 
22
- # Converts the specified float value to a pt value from the
23
- # specified unit of measurement (e.g., in, cm, mm, etc).
24
- # Raises an argument error if the unit of measurement is not recognized.
25
- def to_pt num, units
26
- units = units.to_s if ::Symbol === units
27
- if units.nil_or_empty?
28
- num
29
- else
30
- case units
31
- when 'pt'
24
+ # Converts the specified float value to a pt value from the
25
+ # specified unit of measurement (e.g., in, cm, mm, etc).
26
+ # Raises an argument error if the unit of measurement is not recognized.
27
+ def to_pt num, units
28
+ units = units.to_s if ::Symbol === units
29
+ if units.nil_or_empty?
32
30
  num
33
- when 'in'
34
- num * 72
35
- when 'mm'
36
- num * (72 / 25.4)
37
- when 'cm'
38
- num * (720 / 25.4)
39
- when 'px'
40
- # assuming canvas of 96 dpi
41
- num * 0.75
42
- when 'pc'
43
- num * 12
44
31
  else
45
- raise ::ArgumentError, %(unknown unit of measurement: #{units})
32
+ case units
33
+ when 'pt'
34
+ num
35
+ when 'in'
36
+ num * 72
37
+ when 'mm'
38
+ num * (72 / 25.4)
39
+ when 'cm'
40
+ num * (720 / 25.4)
41
+ when 'px'
42
+ # assuming canvas of 96 dpi
43
+ num * 0.75
44
+ when 'pc'
45
+ num * 12
46
+ else
47
+ raise ::ArgumentError, %(unknown unit of measurement: #{units})
48
+ end
46
49
  end
47
50
  end
48
- end
49
51
 
50
- # Resolve measurement values in the string to PDF points.
51
- def resolve_measurement_values str
52
- if MeasurementValueHintRx.match? str
53
- str.gsub(InsetMeasurementValueRx) { to_pt $1.to_f, $2 }
54
- else
55
- str
52
+ # Resolve measurement values in the string to PDF points.
53
+ def resolve_measurement_values str
54
+ if MeasurementValueHintRx.match? str
55
+ str.gsub(InsetMeasurementValueRx) { to_pt $1.to_f, $2 }
56
+ else
57
+ str
58
+ end
56
59
  end
57
60
  end
58
61
  end
59
- end; end
62
+ end
@@ -1,41 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname'
1
4
  require 'rghost'
2
5
  require 'tmpdir'
3
6
 
4
7
  module Asciidoctor
5
- module PDF
6
- class Optimizer
7
- (QUALITY_NAMES = {
8
- 'default' => :default,
9
- 'screen' => :screen,
10
- 'ebook' => :ebook,
11
- 'printer' => :printer,
12
- 'prepress' => :prepress,
13
- }).default = :default
8
+ module PDF
9
+ class Optimizer
10
+ (QUALITY_NAMES = {
11
+ 'default' => :default,
12
+ 'screen' => :screen,
13
+ 'ebook' => :ebook,
14
+ 'printer' => :printer,
15
+ 'prepress' => :prepress,
16
+ }).default = :default
14
17
 
15
- def initialize quality = 'default', compatibility_level = '1.4'
16
- @quality = QUALITY_NAMES[quality]
17
- @compatibility_level = compatibility_level
18
- end
18
+ def initialize quality = 'default', compatibility_level = '1.4'
19
+ @quality = QUALITY_NAMES[quality]
20
+ @compatibility_level = compatibility_level
21
+ end
19
22
 
20
- def generate_file target
21
- ::Dir::Tmpname.create ['asciidoctor-pdf-', '.pdf'] do |tmpfile|
22
- filename = Pathname.new target
23
- filename_o = Pathname.new tmpfile
24
- pdfmark = filename.sub_ext '.pdfmark'
25
- inputs = pdfmark.file? ? [target, pdfmark.to_s] : target
26
- (::RGhost::Convert.new inputs).to :pdf,
27
- filename: filename_o.to_s,
28
- quality: @quality,
29
- d: { Printed: false, CannotEmbedFontPolicy: '/Warning', CompatibilityLevel: @compatibility_level }
30
- begin
31
- filename_o.rename target
32
- rescue ::Errno::EXDEV
33
- filename.binwrite filename_o.binread
34
- filename_o.unlink
23
+ def generate_file target
24
+ ::Dir::Tmpname.create ['asciidoctor-pdf-', '.pdf'] do |tmpfile|
25
+ filename = Pathname.new target
26
+ filename_o = Pathname.new tmpfile
27
+ pdfmark = filename.sub_ext '.pdfmark'
28
+ inputs = pdfmark.file? ? [target, pdfmark.to_s] : target
29
+ (::RGhost::Convert.new inputs).to :pdf,
30
+ filename: filename_o.to_s,
31
+ quality: @quality,
32
+ d: { Printed: false, CannotEmbedFontPolicy: '/Warning', CompatibilityLevel: @compatibility_level }
33
+ begin
34
+ filename_o.rename target
35
+ rescue ::Errno::EXDEV
36
+ filename.binwrite filename_o.binread
37
+ filename_o.unlink
38
+ end
39
+ end
40
+ nil
35
41
  end
36
42
  end
37
- nil
38
43
  end
39
44
  end
40
- end
41
- end
@@ -1,40 +1,41 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Asciidoctor
3
- module PDF
4
- class Pdfmark
5
- include ::Asciidoctor::PDF::Sanitizer
4
+ module PDF
5
+ class Pdfmark
6
+ include ::Asciidoctor::PDF::Sanitizer
6
7
 
7
- def initialize doc
8
- @doc = doc
9
- end
8
+ def initialize doc
9
+ @doc = doc
10
+ end
10
11
 
11
- def generate
12
- doc = @doc
13
- if doc.attr? 'reproducible'
14
- mod_date = creation_date = (::Time.at 0).utc
15
- else
16
- mod_date = (::Time.parse doc.attr 'docdatetime') rescue (now ||= ::Time.now)
17
- creation_date = (::Time.parse doc.attr 'localdatetime') rescue (now ||= ::Time.now)
18
- end
19
- # FIXME use sanitize: :plain_text once available
20
- content = <<~EOS
21
- [ /Title #{sanitize(doc.doctitle use_fallback: true).to_pdf_object}
22
- /Author #{(doc.attr 'authors').to_pdf_object}
23
- /Subject #{(doc.attr 'subject').to_pdf_object}
24
- /Keywords #{(doc.attr 'keywords').to_pdf_object}
25
- /ModDate #{mod_date.to_pdf_object}
26
- /CreationDate #{creation_date.to_pdf_object}
27
- /Creator (Asciidoctor PDF #{::Asciidoctor::PDF::VERSION}, based on Prawn #{::Prawn::VERSION})
28
- /Producer #{(doc.attr 'publisher').to_pdf_object}
29
- /DOCINFO pdfmark
30
- EOS
31
- content
32
- end
12
+ def generate
13
+ doc = @doc
14
+ if doc.attr? 'reproducible'
15
+ mod_date = creation_date = (::Time.at 0).utc
16
+ else
17
+ mod_date = (::Time.parse doc.attr 'docdatetime') rescue (now ||= ::Time.now)
18
+ creation_date = (::Time.parse doc.attr 'localdatetime') rescue (now || ::Time.now)
19
+ end
20
+ # FIXME: use sanitize: :plain_text once available
21
+ content = <<~EOS
22
+ [ /Title #{(sanitize doc.doctitle use_fallback: true).to_pdf_object}
23
+ /Author #{(doc.attr 'authors').to_pdf_object}
24
+ /Subject #{(doc.attr 'subject').to_pdf_object}
25
+ /Keywords #{(doc.attr 'keywords').to_pdf_object}
26
+ /ModDate #{mod_date.to_pdf_object}
27
+ /CreationDate #{creation_date.to_pdf_object}
28
+ /Creator (Asciidoctor PDF #{::Asciidoctor::PDF::VERSION}, based on Prawn #{::Prawn::VERSION})
29
+ /Producer #{(doc.attr 'publisher').to_pdf_object}
30
+ /DOCINFO pdfmark
31
+ EOS
32
+ content
33
+ end
33
34
 
34
- def generate_file pdf_file
35
- # QUESTION should we use the extension pdfmeta to be more clear?
36
- ::File.write %(#{pdf_file}mark), generate
35
+ def generate_file pdf_file
36
+ # QUESTION should we use the extension pdfmeta to be more clear?
37
+ ::File.write %(#{pdf_file}mark), generate
38
+ end
39
+ end
37
40
  end
38
41
  end
39
- end
40
- end