asciidoctor-pdf 1.5.0.alpha.8 → 1.5.0.alpha.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +9 -1
  3. data/Rakefile +1 -0
  4. data/data/fonts/{LICENSE-noto-fonts-2014-11-17 → LICENSE-noto-2015-06-05} +0 -0
  5. data/data/fonts/{mplus1mn-bolditalic-ascii.ttf → mplus1mn-bold_italic-ascii.ttf} +0 -0
  6. data/data/fonts/{mplus1p-regular-multilingual.ttf → mplus1p-regular-fallback.ttf} +0 -0
  7. data/data/fonts/notoserif-bold-subset.ttf +0 -0
  8. data/data/fonts/notoserif-bold_italic-subset.ttf +0 -0
  9. data/data/fonts/notoserif-italic-subset.ttf +0 -0
  10. data/data/fonts/notoserif-regular-subset.ttf +0 -0
  11. data/data/themes/base-theme.yml +90 -0
  12. data/data/themes/default-theme.yml +97 -92
  13. data/docs/theming-guide.adoc +93 -21
  14. data/lib/asciidoctor-pdf/converter.rb +419 -216
  15. data/lib/asciidoctor-pdf/core_ext/quantifiable_stdout.rb +20 -0
  16. data/lib/asciidoctor-pdf/formatted_text/formatter.rb +6 -5
  17. data/lib/asciidoctor-pdf/formatted_text/inline_image_arranger.rb +3 -3
  18. data/lib/asciidoctor-pdf/formatted_text/transform.rb +36 -26
  19. data/lib/asciidoctor-pdf/pdf_core_ext.rb +1 -1
  20. data/lib/asciidoctor-pdf/pdf_core_ext/page.rb +22 -0
  21. data/lib/asciidoctor-pdf/prawn_ext.rb +1 -0
  22. data/lib/asciidoctor-pdf/prawn_ext/coderay_encoder.rb +24 -4
  23. data/lib/asciidoctor-pdf/prawn_ext/extensions.rb +73 -6
  24. data/lib/asciidoctor-pdf/prawn_ext/font/afm.rb +19 -0
  25. data/lib/asciidoctor-pdf/prawn_ext/formatted_text/fragment.rb +1 -1
  26. data/lib/asciidoctor-pdf/prawn_ext/images.rb +16 -0
  27. data/lib/asciidoctor-pdf/rouge_ext.rb +4 -0
  28. data/lib/asciidoctor-pdf/rouge_ext/css_theme.rb +14 -0
  29. data/lib/asciidoctor-pdf/rouge_ext/formatters/prawn.rb +121 -0
  30. data/lib/asciidoctor-pdf/rouge_ext/themes/pastie.rb +61 -0
  31. data/lib/asciidoctor-pdf/theme_loader.rb +32 -14
  32. data/lib/asciidoctor-pdf/version.rb +1 -1
  33. metadata +23 -15
  34. data/data/fonts/notoserif-bold-latin.ttf +0 -0
  35. data/data/fonts/notoserif-bolditalic-latin.ttf +0 -0
  36. data/data/fonts/notoserif-italic-latin.ttf +0 -0
  37. data/data/fonts/notoserif-regular-latin.ttf +0 -0
@@ -23,7 +23,7 @@ module Fragment
23
23
  end
24
24
 
25
25
  class ::Prawn::Text::Formatted::Fragment
26
- if ::RUBY_MIN_VERSION_2
26
+ if respond_to? :prepend
27
27
  prepend Fragment
28
28
  else
29
29
  # NOTE it's necessary to remove the accessor methods or else they won't get replaced
@@ -17,6 +17,22 @@ module Images
17
17
  _initial_image file, opts
18
18
  end
19
19
  end
20
+
21
+ # Retrieve the intrinsic image dimensions for the specified path.
22
+ #
23
+ # Returns a Hash containing :width and :height keys that map to the image's
24
+ # intrinsic width and height values (in pixels)
25
+ def intrinsic_image_dimensions path
26
+ if path.end_with? '.svg'
27
+ img_obj = ::Prawn::Svg::Interface.new ::IO.read(path), self, {}
28
+ img_size = img_obj.document.sizing
29
+ { width: img_size.output_width, height: img_size.output_height }
30
+ else
31
+ # NOTE build_image_object caches image data previously loaded
32
+ _, img_size = build_image_object path
33
+ { width: img_size.width, height: img_size.height }
34
+ end
35
+ end
20
36
  end
21
37
 
22
38
  ::Prawn::Document.extensions << Images
@@ -0,0 +1,4 @@
1
+ require 'rouge'
2
+ require_relative 'rouge_ext/formatters/prawn'
3
+ require_relative 'rouge_ext/css_theme'
4
+ require_relative 'rouge_ext/themes/pastie'
@@ -0,0 +1,14 @@
1
+ module Rouge
2
+ class CSSTheme
3
+ # Patch style_for to return most specific style first
4
+ # See https://github.com/jneen/rouge/issues/280 (fix pending)
5
+ def style_for token
6
+ token.token_chain.reverse_each do |t|
7
+ if (s = styles[t])
8
+ return s
9
+ end
10
+ end
11
+ nil
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,121 @@
1
+ module Rouge
2
+ module Formatters
3
+ # Transforms a token stream into an array of
4
+ # formatted text fragments for use with Prawn.
5
+ class Prawn < Formatter
6
+ tag 'prawn'
7
+
8
+ EOL = %(\n)
9
+ NoBreakSpace = %(\u00a0)
10
+ InnerIndent = %(\n )
11
+ GuardedIndent = %(\u00a0)
12
+ GuardedInnerIndent = %(\n\u00a0)
13
+ BoldStyle = [:bold].to_set
14
+ ItalicStyle = [:italic].to_set
15
+ BoldItalicStyle = [:bold, :italic].to_set
16
+
17
+ def initialize opts = {}
18
+ unless ::Rouge::Theme === (theme = opts[:theme])
19
+ unless theme && (theme = ::Rouge::Theme.find theme)
20
+ theme = ::Rouge::Themes::Pastie
21
+ end
22
+ theme = theme.new
23
+ end
24
+ @theme = theme
25
+ @normalized_colors = {}
26
+ @linenum_fragment_base = (create_fragment Token['Generic.Lineno']).merge linenum: true
27
+ end
28
+
29
+ # Override format method so fragments don't get flatted to a string
30
+ # and to add an options Hash.
31
+ def format tokens, opts = {}
32
+ stream tokens, opts
33
+ end
34
+
35
+ def stream tokens, opts = {}
36
+ if opts[:line_numbers]
37
+ # TODO implement line number start (offset)
38
+ linenum = 0
39
+ fragments = []
40
+ fragments << (create_linenum_fragment linenum += 1)
41
+ tokens.each do |tok, val|
42
+ if val == EOL
43
+ fragments << { text: EOL }
44
+ fragments << (create_linenum_fragment linenum += 1)
45
+ elsif val.include? EOL
46
+ base_fragment = create_fragment tok, val
47
+ val.each_line do |line|
48
+ fragments << (base_fragment.merge text: line)
49
+ # NOTE append linenum fragment if there's a next line; only works if source doesn't have trailing endline
50
+ if line.end_with? EOL
51
+ fragments << (create_linenum_fragment linenum += 1)
52
+ end
53
+ end
54
+ else
55
+ fragments << (create_fragment tok, val)
56
+ end
57
+ end
58
+ # NOTE drop orphaned linenum fragment (due to trailing endline in source)
59
+ fragments.pop if (last_fragment = fragments[-1]) && last_fragment[:linenum]
60
+ # NOTE pad numbers that have less digits than the largest line number
61
+ if (linenum_w = (linenum / 10) + 1) > 1
62
+ # NOTE extra column is the trailing space after the line number
63
+ linenum_w += 1
64
+ fragments.each do |fragment|
65
+ fragment[:text] = %(#{fragment[:text].rjust linenum_w, NoBreakSpace}) if fragment[:linenum]
66
+ end
67
+ end
68
+ fragments
69
+ else
70
+ start_of_line = true
71
+ tokens.map do |tok, val|
72
+ # match one or more consecutive endlines
73
+ if val == EOL || (val == (EOL * val.length))
74
+ start_of_line = true
75
+ { text: val }
76
+ else
77
+ val[0] = GuardedIndent if start_of_line && (val.start_with? ' ')
78
+ val.gsub! InnerIndent, GuardedInnerIndent if val.include? InnerIndent
79
+ start_of_line = val.end_with? EOL
80
+ # NOTE this optimization assumes we don't support/use background colors
81
+ val.rstrip.empty? ? { text: val } : (create_fragment tok, val)
82
+ end
83
+ end
84
+ # QUESTION should we strip trailing newline?
85
+ end
86
+ end
87
+
88
+ # TODO method could still be optimized (for instance, check if val is EOL or empty)
89
+ def create_fragment tok, val = nil
90
+ fragment = val ? { text: val } : {}
91
+ if (style_rules = @theme.style_for tok)
92
+ # TODO support background color
93
+ if (fg = normalize_color style_rules.fg)
94
+ fragment[:color] = fg
95
+ end
96
+ if style_rules[:bold]
97
+ fragment[:styles] = style_rules[:italic] ? BoldItalicStyle : BoldStyle
98
+ elsif style_rules[:italic]
99
+ fragment[:styles] = ItalicStyle
100
+ end
101
+ end
102
+ fragment
103
+ end
104
+
105
+ def create_linenum_fragment linenum
106
+ @linenum_fragment_base.merge text: %(#{linenum} )
107
+ end
108
+
109
+ def normalize_color raw
110
+ return unless raw
111
+ if (normalized = @normalized_colors[raw])
112
+ normalized
113
+ else
114
+ normalized = (raw.start_with? '#') ? raw[1..-1] : raw
115
+ normalized = normalized.each_char.map {|c| c * 2 }.join if normalized.size == 3
116
+ @normalized_colors[raw] = normalized
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,61 @@
1
+ module Rouge
2
+ module Themes
3
+ # A Rouge theme that matches the pastie style from Pygments.
4
+ # See https://bitbucket.org/birkenfeld/pygments-main/src/default/pygments/styles/pastie.py
5
+ class Pastie < CSSTheme
6
+ name 'pastie'
7
+
8
+ style Text::Whitespace, fg: '#bbbbbb'
9
+
10
+ style Comment, fg: '#888888'
11
+ style Comment::Preproc, fg: '#cc0000', bold: true
12
+ style Comment::Special, fg: '#cc0000', bg: '#fff0f0', bold: true
13
+
14
+ style Error, fg: '#a61717', bg: '#e3d2d2'
15
+ style Generic::Error, fg: '#aa0000'
16
+ style Generic::Traceback, fg: '#aa0000'
17
+
18
+ style Generic::Deleted, fg: '#000000', bg: '#ffdddd'
19
+ style Generic::Emph, italic: true
20
+ style Generic::Inserted, fg: '#000000', bg: '#ddffdd'
21
+ style Generic::Heading, fg: '#333333'
22
+ #style Generic::Lineno, fg: '#555555'
23
+ style Generic::Lineno, fg: '#888888'
24
+ style Generic::Output, fg: '#888888'
25
+ style Generic::Prompt, fg: '#555555'
26
+ style Generic::Strong, bold: true
27
+ style Generic::Subheading, fg: '#666666'
28
+
29
+ style Keyword, fg: '#008800', bold: true
30
+ style Keyword::Pseudo, fg: '#008800'
31
+ style Keyword::Type, fg: '#888888', bold: true
32
+
33
+ style Literal::Number, fg: '#0000dd', bold: true
34
+
35
+ style Literal::String, fg: '#dd2200', bg: '#fff0f0'
36
+ style Literal::String::Escape, fg: '#0044dd'
37
+ style Literal::String::Interpol, fg: '#3333bb'
38
+ style Literal::String::Other, fg: '#22bb22', bg: '#f0fff0'
39
+ style Literal::String::Regex, fg: '#008800', bg: '#fff0ff'
40
+ style Literal::String::Symbol, fg: '#aa6600'
41
+
42
+ style Name::Attribute, fg: '#336699'
43
+ style Name::Builtin, fg: '#003388'
44
+ style Name::Class, fg: '#bb0066', bold: true
45
+ style Name::Constant, fg: '#003366', bold: true
46
+ style Name::Decorator, fg: '#555555'
47
+ style Name::Exception, fg: '#bb0066', bold: true
48
+ style Name::Function, fg: '#0066bb', bold: true
49
+ #style Name::Label, fg: '#336699', italic: true
50
+ style Name::Label, fg: '#336699'
51
+ style Name::Namespace, fg: '#bb0066', bold: true
52
+ style Name::Property, fg: '#336699', bold: true
53
+ style Name::Tag, fg: '#bb0066', bold: true
54
+ style Name::Variable::Global, fg: '#dd7700'
55
+ style Name::Variable::Instance, fg: '#3333bb'
56
+ style Name::Variable, fg: '#336699'
57
+
58
+ style Operator::Word, fg: '#008800'
59
+ end
60
+ end
61
+ end
@@ -8,6 +8,8 @@ class ThemeLoader
8
8
  DataDir = ::File.expand_path(::File.join(::File.dirname(__FILE__), '..', '..', 'data'))
9
9
  ThemesDir = ::File.join DataDir, 'themes'
10
10
  FontsDir = ::File.join DataDir, 'fonts'
11
+ DefaultThemePath = ::File.expand_path 'default-theme.yml', ThemesDir
12
+ BaseThemePath = ::File.expand_path 'base-theme.yml', ThemesDir
11
13
 
12
14
  VariableRx = /\$([a-z0-9_]+)/
13
15
  LoneVariableRx = /^\$([a-z0-9_]+)$/
@@ -39,32 +41,48 @@ class ThemeLoader
39
41
  if (theme_name.end_with? '.yml')
40
42
  # FIXME restrict to jail!
41
43
  # QUESTION why are we not using expand_path in this case?
42
- theme_path ? ::File.join(theme_path, theme_name) : theme_name
44
+ theme_path ? (::File.join theme_path, theme_name) : theme_name
43
45
  else
44
46
  # QUESTION should we append '-theme.yml' or just '.yml'?
45
- ::File.expand_path(%(#{theme_name}-theme.yml), (theme_path || ThemesDir))
47
+ ::File.expand_path %(#{theme_name}-theme.yml), (theme_path || ThemesDir)
46
48
  end
47
49
  end
48
50
 
49
51
  def self.resolve_theme_asset asset_path, theme_path = nil
50
- ::File.expand_path(asset_path, (theme_path || ThemesDir))
52
+ ::File.expand_path asset_path, (theme_path || ThemesDir)
51
53
  end
52
54
 
53
- def self.load_theme theme_name = nil, theme_path = nil
54
- load_file(resolve_theme_file theme_name, theme_path)
55
+ # NOTE base theme is loaded "as is" (no post-processing)
56
+ def self.load_base_theme
57
+ ::OpenStruct.new(::SafeYAML.load_file BaseThemePath)
55
58
  end
56
59
 
57
- def self.load_file filename
58
- data = ::IO.read(filename).each_line.map {|l| l.sub HexColorValueRx, '_color: \'\k<value>\'' }.join
59
- self.new.load(::SafeYAML.load data)
60
- end
60
+ def self.load_theme theme_name = nil, theme_path = nil, opts = {}
61
+ if (theme_file = resolve_theme_file theme_name, theme_path) == BaseThemePath ||
62
+ (theme_file != DefaultThemePath && (opts.fetch :apply_base_theme, true))
63
+ theme_data = load_base_theme
64
+ else
65
+ theme_data = nil
66
+ end
61
67
 
62
- def load hash
63
- hash.inject(::OpenStruct.new) do |data, (key, val)|
64
- process_entry key, val, data
68
+ if theme_file == BaseThemePath
69
+ theme_data
70
+ else
71
+ # QUESTION should we do any post-load calculations or defaults?
72
+ load_file theme_file, theme_data
65
73
  end
66
74
  end
67
75
 
76
+ def self.load_file filename, theme_data = nil
77
+ raw_data = (::IO.read filename).each_line.map {|l| l.sub HexColorValueRx, '_color: \'\k<value>\'' }.join
78
+ self.new.load((::SafeYAML.load raw_data), theme_data)
79
+ end
80
+
81
+ def load hash, theme_data = nil
82
+ theme_data ||= ::OpenStruct.new
83
+ hash.inject(theme_data) {|data, (key, val)| process_entry key, val, data }
84
+ end
85
+
68
86
  private
69
87
 
70
88
  def process_entry key, val, data
@@ -92,7 +110,7 @@ class ThemeLoader
92
110
  # NOTE we assume expr is a String
93
111
  def expand_vars expr, vars
94
112
  if (idx = (expr.index '$'))
95
- if idx == 0 && LoneVariableRx =~ expr
113
+ if idx == 0 && expr =~ LoneVariableRx
96
114
  vars[$1]
97
115
  else
98
116
  expr.gsub(VariableRx) { vars[$1] }
@@ -137,7 +155,7 @@ class ThemeLoader
137
155
  expr = result
138
156
  break if unchanged
139
157
  end
140
- if (expr.end_with? ')') && PrecisionFuncRx =~ expr
158
+ if (expr.end_with? ')') && expr =~ PrecisionFuncRx
141
159
  op = $1
142
160
  offset = op.length + 1
143
161
  expr = expr[offset...-1].to_f.send op.to_sym
@@ -1,5 +1,5 @@
1
1
  module Asciidoctor
2
2
  module Pdf
3
- VERSION = '1.5.0.alpha.8'
3
+ VERSION = '1.5.0.alpha.9'
4
4
  end
5
5
  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: 1.5.0.alpha.8
4
+ version: 1.5.0.alpha.9
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: 2015-06-24 00:00:00.000000000 Z
12
+ date: 2015-08-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -65,14 +65,14 @@ dependencies:
65
65
  requirements:
66
66
  - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: 0.2.1
68
+ version: 0.2.2
69
69
  type: :runtime
70
70
  prerelease: false
71
71
  version_requirements: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: 0.2.1
75
+ version: 0.2.2
76
76
  - !ruby/object:Gem::Dependency
77
77
  name: prawn-templates
78
78
  requirement: !ruby/object:Gem::Requirement
@@ -93,14 +93,14 @@ dependencies:
93
93
  requirements:
94
94
  - - '='
95
95
  - !ruby/object:Gem::Version
96
- version: 0.20.0
96
+ version: 0.21.0
97
97
  type: :runtime
98
98
  prerelease: false
99
99
  version_requirements: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - '='
102
102
  - !ruby/object:Gem::Version
103
- version: 0.20.0
103
+ version: 0.21.0
104
104
  - !ruby/object:Gem::Dependency
105
105
  name: prawn-icon
106
106
  requirement: !ruby/object:Gem::Requirement
@@ -135,14 +135,14 @@ dependencies:
135
135
  requirements:
136
136
  - - '='
137
137
  - !ruby/object:Gem::Version
138
- version: 0.3.4
138
+ version: 0.3.5
139
139
  type: :runtime
140
140
  prerelease: false
141
141
  version_requirements: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - '='
144
144
  - !ruby/object:Gem::Version
145
- version: 0.3.4
145
+ version: 0.3.5
146
146
  - !ruby/object:Gem::Dependency
147
147
  name: treetop
148
148
  requirement: !ruby/object:Gem::Requirement
@@ -175,16 +175,17 @@ files:
175
175
  - bin/asciidoctor-pdf
176
176
  - bin/optimize-pdf
177
177
  - data/fonts/LICENSE-mplus-testflight-58
178
- - data/fonts/LICENSE-noto-fonts-2014-11-17
178
+ - data/fonts/LICENSE-noto-2015-06-05
179
179
  - data/fonts/mplus1mn-bold-ascii.ttf
180
- - data/fonts/mplus1mn-bolditalic-ascii.ttf
180
+ - data/fonts/mplus1mn-bold_italic-ascii.ttf
181
181
  - data/fonts/mplus1mn-italic-ascii.ttf
182
182
  - data/fonts/mplus1mn-regular-ascii-conums.ttf
183
- - data/fonts/mplus1p-regular-multilingual.ttf
184
- - data/fonts/notoserif-bold-latin.ttf
185
- - data/fonts/notoserif-bolditalic-latin.ttf
186
- - data/fonts/notoserif-italic-latin.ttf
187
- - data/fonts/notoserif-regular-latin.ttf
183
+ - data/fonts/mplus1p-regular-fallback.ttf
184
+ - data/fonts/notoserif-bold-subset.ttf
185
+ - data/fonts/notoserif-bold_italic-subset.ttf
186
+ - data/fonts/notoserif-italic-subset.ttf
187
+ - data/fonts/notoserif-regular-subset.ttf
188
+ - data/themes/base-theme.yml
188
189
  - data/themes/default-theme.yml
189
190
  - docs/theme-schema.json
190
191
  - docs/theming-guide.adoc
@@ -199,6 +200,7 @@ files:
199
200
  - lib/asciidoctor-pdf/core_ext/array.rb
200
201
  - lib/asciidoctor-pdf/core_ext/numeric.rb
201
202
  - lib/asciidoctor-pdf/core_ext/ostruct.rb
203
+ - lib/asciidoctor-pdf/core_ext/quantifiable_stdout.rb
202
204
  - lib/asciidoctor-pdf/formatted_text.rb
203
205
  - lib/asciidoctor-pdf/formatted_text/formatter.rb
204
206
  - lib/asciidoctor-pdf/formatted_text/inline_destination_marker.rb
@@ -209,14 +211,20 @@ files:
209
211
  - lib/asciidoctor-pdf/formatted_text/transform.rb
210
212
  - lib/asciidoctor-pdf/implicit_header_processor.rb
211
213
  - lib/asciidoctor-pdf/pdf_core_ext.rb
214
+ - lib/asciidoctor-pdf/pdf_core_ext/page.rb
212
215
  - lib/asciidoctor-pdf/pdf_core_ext/pdf_object.rb
213
216
  - lib/asciidoctor-pdf/pdfmarks.rb
214
217
  - lib/asciidoctor-pdf/prawn_ext.rb
215
218
  - lib/asciidoctor-pdf/prawn_ext/coderay_encoder.rb
216
219
  - lib/asciidoctor-pdf/prawn_ext/extensions.rb
220
+ - lib/asciidoctor-pdf/prawn_ext/font/afm.rb
217
221
  - lib/asciidoctor-pdf/prawn_ext/formatted_text/fragment.rb
218
222
  - lib/asciidoctor-pdf/prawn_ext/images.rb
219
223
  - lib/asciidoctor-pdf/roman_numeral.rb
224
+ - lib/asciidoctor-pdf/rouge_ext.rb
225
+ - lib/asciidoctor-pdf/rouge_ext/css_theme.rb
226
+ - lib/asciidoctor-pdf/rouge_ext/formatters/prawn.rb
227
+ - lib/asciidoctor-pdf/rouge_ext/themes/pastie.rb
220
228
  - lib/asciidoctor-pdf/sanitizer.rb
221
229
  - lib/asciidoctor-pdf/temporary_path.rb
222
230
  - lib/asciidoctor-pdf/theme_loader.rb