asciidoctor 2.0.20 → 2.0.21

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 95bddd5f820dc0441d3accb7dd49864b1fb9f1807823887d0075e595a2d55094
4
- data.tar.gz: 1dd21111bda88dde555fe981b30e89684bd0ac0bbe8e329721bbdc7b18ab806d
3
+ metadata.gz: eb33ff3290649511b70addaa88b8b1ef9429641bc0cf04113b8fe8613ac6ad63
4
+ data.tar.gz: 6c26157b4e3a366c43b2ef6a2fffcad558b3a3363fc3985ca7a1b2412292d192
5
5
  SHA512:
6
- metadata.gz: a03b03f8a1bda4d71235f975603353c9653c1ad98ff26a42b5d2d844dab6954c41d75c45d598a8b976bba3b4b35aa05f7e2791c1dc6c1da75714bced767f6f8f
7
- data.tar.gz: c463c0c23a75ddadf2c1eff1cc3afdf574b07a2551693b7330a1cebcef8a9e789ffa5f9bec005843a327837d33f42298f30684f6d16a8c0271d1379ac080485e
6
+ metadata.gz: 72aca517f60e682e3038e8f790669de5e00f86f6b3d20be023b090bff7e837f866e2211e67657ba5139ca9758f9b260ffff70edf597b060d371e2e1ffc09e1e7
7
+ data.tar.gz: efcc562d749e9fafc3462598490a9b03a0f556919a55c1fb0c5f04635006ac006800dd6607388bacef5d837aeb7f3d2951ed11069675dae5555b84ce8945bcf3
data/CHANGELOG.adoc CHANGED
@@ -16,6 +16,38 @@ For an even more detailed look at what has changed, refer to the {url-repo}/comm
16
16
  This project utilizes semantic versioning.
17
17
 
18
18
  // tag::compact[]
19
+ == 2.0.21 (2024-02-20) - @mojavelinux
20
+
21
+ Compliance::
22
+
23
+ * Turn off system-dependent newline conversion when writing files; don't convert line feeds to system-dependent newline (#4550)
24
+ * Support logger in Ruby 3.3 by instantiating super class (#4493) (*@mtasaka*)
25
+ * Add support for `scaledwidth` and `scale` attributes on inline image macro in DocBook output (#4552)
26
+ * Update latest Ruby to 3.3 in CI workflows
27
+
28
+ Improvements::
29
+
30
+ * Change title to doctitle in warning message about use of abstract to make subject more clear
31
+ * Modify default stylesheet to add text decoration to active footnote number link in footnotes list (#4530) (@Larhzu)
32
+
33
+ Bug Fixes::
34
+
35
+ * Nested dlist attached using list continuation should not consume detached paragraph (#3535)
36
+ * Don't break nested dlist with attached block if offset from parent list by empty line (#3693)
37
+ * Preserve paragraph breaks in normal table cell in manpage output (#4481)
38
+ * Style cells in head row as bold in manpage output (#4490)
39
+ * Escape spaces in include target (using inline passthrough) when generating link from include directive (#4461)
40
+ * Move abstract inside info tag in DocBook output (#3602)
41
+ * Honor secondary and tertiary terms on `indexterm` macro when primary term is quoted and contains an equals sign (#3652)
42
+ * Remove extra border below doctitle when sidebar toc is collapsed into main content area (#4523)
43
+ * Treat bare URL enclosed in angle brackets as unconstrained syntax; only match until closing angled bracket (#4468)
44
+ * Allow URL enclosed in angled brackets syntax to be escaped using backslash (#4468)
45
+
46
+ === Details
47
+
48
+ {url-repo}/releases/tag/v2.0.21[git tag] | {url-repo}/compare/v2.0.20\...v2.0.21[full diff]
49
+ // end::compact[]
50
+
19
51
  == 2.0.20 (2023-05-18) - @mojavelinux
20
52
 
21
53
  Bug Fixes::
@@ -26,7 +58,6 @@ Bug Fixes::
26
58
  === Details
27
59
 
28
60
  {url-repo}/releases/tag/v2.0.20[git tag] | {url-repo}/compare/v2.0.19\...v2.0.20[full diff]
29
- // end::compact[]
30
61
 
31
62
  == 2.0.19 (2023-05-17) - @mojavelinux
32
63
 
data/README-de.adoc CHANGED
@@ -1,6 +1,6 @@
1
1
  = Asciidoctor
2
2
  Dan Allen <https://github.com/mojavelinux[@mojavelinux]>; Sarah White <https://github.com/graphitefriction[@graphitefriction]>
3
- v2.0.20, 2023-05-18
3
+ v2.0.21, 2024-02-20
4
4
  // settings:
5
5
  :idprefix:
6
6
  :idseparator: -
@@ -16,7 +16,7 @@ ifdef::env-github[]
16
16
  :warning-caption: :warning:
17
17
  endif::[]
18
18
  // Variables:
19
- :release-version: 2.0.20
19
+ :release-version: 2.0.21
20
20
  // URIs:
21
21
  :uri-org: https://github.com/asciidoctor
22
22
  :uri-repo: {uri-org}/asciidoctor
data/README-fr.adoc CHANGED
@@ -1,6 +1,6 @@
1
1
  = Asciidoctor
2
2
  Dan Allen <https://github.com/mojavelinux[@mojavelinux]>; Sarah White <https://github.com/graphitefriction[@graphitefriction]>
3
- v2.0.20, 2023-05-18
3
+ v2.0.21, 2024-02-20
4
4
  // settings:
5
5
  :idprefix:
6
6
  :idseparator: -
@@ -16,7 +16,7 @@ ifdef::env-github[]
16
16
  :warning-caption: :warning:
17
17
  endif::[]
18
18
  // Variables:
19
- :release-version: 2.0.20
19
+ :release-version: 2.0.21
20
20
  // URIs:
21
21
  :uri-org: https://github.com/asciidoctor
22
22
  :uri-repo: {uri-org}/asciidoctor
data/README-jp.adoc CHANGED
@@ -1,6 +1,6 @@
1
1
  = Asciidoctor
2
2
  Dan Allen <https://github.com/mojavelinux[@mojavelinux]>; Sarah White <https://github.com/graphitefriction[@graphitefriction]>
3
- v2.0.20, 2023-05-18
3
+ v2.0.21, 2024-02-20
4
4
  // settings:
5
5
  :idprefix:
6
6
  :idseparator: -
@@ -16,7 +16,7 @@ ifdef::env-github[]
16
16
  :warning-caption: :warning:
17
17
  endif::[]
18
18
  // Variables:
19
- :release-version: 2.0.20
19
+ :release-version: 2.0.21
20
20
  // URIs:
21
21
  :uri-org: https://github.com/asciidoctor
22
22
  :uri-repo: {uri-org}/asciidoctor
data/README-zh_CN.adoc CHANGED
@@ -1,6 +1,6 @@
1
1
  = Asciidoctor
2
2
  Dan Allen <https://github.com/mojavelinux[@mojavelinux]>; Sarah White <https://github.com/graphitefriction[@graphitefriction]>
3
- v2.0.20, 2023-05-18
3
+ v2.0.21, 2024-02-20
4
4
  // settings:
5
5
  :page-layout: base
6
6
  :idprefix:
@@ -17,7 +17,7 @@ ifdef::env-github[]
17
17
  :warning-caption: :warning:
18
18
  endif::[]
19
19
  // Variables:
20
- :release-version: 2.0.20
20
+ :release-version: 2.0.21
21
21
  // URIs:
22
22
  :uri-org: https://github.com/asciidoctor
23
23
  :uri-repo: {uri-org}/asciidoctor
data/README.adoc CHANGED
@@ -1,6 +1,6 @@
1
1
  = Asciidoctor
2
2
  Dan Allen <https://github.com/mojavelinux[@mojavelinux]>; Sarah White <https://github.com/graphitefriction[@graphitefriction]>
3
- v2.0.20, 2023-05-18
3
+ v2.0.21, 2024-02-20
4
4
  // settings:
5
5
  :idprefix:
6
6
  :idseparator: -
@@ -16,7 +16,7 @@ ifdef::env-github[]
16
16
  :warning-caption: :warning:
17
17
  endif::[]
18
18
  // Variables:
19
- :release-version: 2.0.20
19
+ :release-version: 2.0.21
20
20
  // URLs:
21
21
  :url-org: https://github.com/asciidoctor
22
22
  :url-repo: {url-org}/asciidoctor
@@ -112,7 +112,7 @@ Attach a block or paragraph to a list item using a list continuation (which you
112
112
 
113
113
  .Some Authors
114
114
  [circle]
115
- - Edgar Allen Poe
115
+ - Edgar Allan Poe
116
116
  - Sheri S. Tepper
117
117
  - Bill Bryson
118
118
 
@@ -130,7 +130,7 @@ p a>code:hover{color:rgba(0,0,0,.9)}
130
130
  #content::before{content:none}
131
131
  #header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
132
132
  #header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}
133
- #header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
133
+ #header>h1:only-child{border-bottom:1px solid #dddddf;padding-bottom:8px}
134
134
  #header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap}
135
135
  #header .details span:first-child{margin-left:-.125em}
136
136
  #header .details span.email a{color:rgba(0,0,0,.85)}
@@ -152,6 +152,7 @@ p a>code:hover{color:rgba(0,0,0,.9)}
152
152
  #toctitle{color:#7a2518;font-size:1.2em}
153
153
  @media screen and (min-width:768px){#toctitle{font-size:1.375em}
154
154
  body.toc2{padding-left:15em;padding-right:0}
155
+ body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
155
156
  #toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
156
157
  #toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
157
158
  #toc.toc2>ul{font-size:.9em;margin-bottom:0}
@@ -317,7 +318,7 @@ a.image{text-decoration:none;display:inline-block}
317
318
  a.image object{pointer-events:none}
318
319
  sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
319
320
  sup.footnote a,sup.footnoteref a{text-decoration:none}
320
- sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
321
+ sup.footnote a:active,sup.footnoteref a:active,#footnotes .footnote a:first-of-type:active{text-decoration:underline}
321
322
  #footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
322
323
  #footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
323
324
  #footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
@@ -44,7 +44,8 @@ class Converter::DocBook5Converter < Converter::Base
44
44
  end
45
45
  root_tag_idx = result.size
46
46
  id = node.id
47
- result << (document_info_tag node) unless node.noheader
47
+ abstract = find_root_abstract node
48
+ result << (document_info_tag node, abstract) unless node.noheader
48
49
  if manpage
49
50
  result << '<refentry>'
50
51
  result << '<refmeta>'
@@ -61,7 +62,9 @@ class Converter::DocBook5Converter < Converter::Base
61
62
  unless (docinfo_content = node.docinfo :header).empty?
62
63
  result << docinfo_content
63
64
  end
64
- result << node.content if node.blocks?
65
+ abstract = extract_abstract node, abstract if abstract
66
+ result << (node.blocks.map {|block| block.convert }.compact.join LF) if node.blocks?
67
+ restore_abstract abstract if abstract
65
68
  unless (docinfo_content = node.docinfo :footer).empty?
66
69
  result << docinfo_content
67
70
  end
@@ -73,7 +76,15 @@ class Converter::DocBook5Converter < Converter::Base
73
76
  result.join LF
74
77
  end
75
78
 
76
- alias convert_embedded content_only
79
+ def convert_embedded node
80
+ # NOTE in DocBook 5, the root abstract must be in the info tag and is thus not part of the body
81
+ if @backend == 'docbook5' && (abstract = find_root_abstract node)
82
+ abstract = extract_abstract node, abstract
83
+ end
84
+ result = node.blocks.map {|block| block.convert }.compact.join LF
85
+ restore_abstract abstract if abstract
86
+ result
87
+ end
77
88
 
78
89
  def convert_section node
79
90
  if node.document.doctype == 'manpage'
@@ -183,27 +194,11 @@ class Converter::DocBook5Converter < Converter::Base
183
194
  end
184
195
 
185
196
  def convert_image node
186
- # NOTE according to the DocBook spec, content area, scaling, and scaling to fit are mutually exclusive
187
- # See http://tdg.docbook.org/tdg/4.5/imagedata-x.html#d0e79635
188
- if node.attr? 'scaledwidth'
189
- width_attribute = %( width="#{node.attr 'scaledwidth'}")
190
- depth_attribute = ''
191
- scale_attribute = ''
192
- elsif node.attr? 'scale'
193
- # QUESTION should we set the viewport using width and depth? (the scaled image would be contained within this box)
194
- #width_attribute = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : ''
195
- #depth_attribute = (node.attr? 'height') ? %( depth="#{node.attr 'height'}") : ''
196
- scale_attribute = %( scale="#{node.attr 'scale'}")
197
- else
198
- width_attribute = (node.attr? 'width') ? %( contentwidth="#{node.attr 'width'}") : ''
199
- depth_attribute = (node.attr? 'height') ? %( contentdepth="#{node.attr 'height'}") : ''
200
- scale_attribute = ''
201
- end
202
197
  align_attribute = (node.attr? 'align') ? %( align="#{node.attr 'align'}") : ''
203
198
 
204
199
  mediaobject = %(<mediaobject>
205
200
  <imageobject>
206
- <imagedata fileref="#{node.image_uri(node.attr 'target')}"#{width_attribute}#{depth_attribute}#{scale_attribute}#{align_attribute}/>
201
+ <imagedata fileref="#{node.image_uri node.attr 'target'}"#{image_size_attributes node.attributes}#{align_attribute}/>
207
202
  </imageobject>
208
203
  <textobject><phrase>#{node.alt}</phrase></textobject>
209
204
  </mediaobject>)
@@ -308,13 +303,17 @@ class Converter::DocBook5Converter < Converter::Base
308
303
  def convert_open node
309
304
  case node.style
310
305
  when 'abstract'
311
- if node.parent == node.document && node.document.doctype == 'book'
312
- logger.warn 'abstract block cannot be used in a document without a title when doctype is book. Excluding block content.'
306
+ if (parent = node.parent) == node.document && node.document.doctype == 'book'
307
+ logger.warn 'abstract block cannot be used in a document without a doctitle when doctype is book. Excluding block content.'
313
308
  ''
314
309
  else
315
- %(<abstract>
310
+ result = %(<abstract>
316
311
  #{title_tag node}#{enclose_content node}
317
312
  </abstract>)
313
+ if @backend == 'docbook5' && !(node.option? 'root') && (parent.context == :open ? parent.style == 'partintro' : parent.context == :section && parent.sectname == 'partintro') && node == parent.blocks[0]
314
+ result = %(<info>\n#{result}\n</info>)
315
+ end
316
+ result
318
317
  end
319
318
  when 'partintro'
320
319
  if node.level == 0 && node.parent.context == :section && node.document.doctype == 'book'
@@ -536,11 +535,9 @@ class Converter::DocBook5Converter < Converter::Base
536
535
  end
537
536
 
538
537
  def convert_inline_image node
539
- width_attribute = (node.attr? 'width') ? %( contentwidth="#{node.attr 'width'}") : ''
540
- depth_attribute = (node.attr? 'height') ? %( contentdepth="#{node.attr 'height'}") : ''
541
538
  %(<inlinemediaobject#{common_attributes nil, node.role}>
542
539
  <imageobject>
543
- <imagedata fileref="#{node.type == 'icon' ? (node.icon_uri node.target) : (node.image_uri node.target)}"#{width_attribute}#{depth_attribute}/>
540
+ <imagedata fileref="#{node.type == 'icon' ? (node.icon_uri node.target) : (node.image_uri node.target)}"#{image_size_attributes node.attributes}/>
544
541
  </imageobject>
545
542
  <textobject><phrase>#{node.alt}</phrase></textobject>
546
543
  </inlinemediaobject>)
@@ -648,6 +645,23 @@ class Converter::DocBook5Converter < Converter::Base
648
645
  end
649
646
  end
650
647
 
648
+ def image_size_attributes attributes
649
+ # NOTE according to the DocBook spec, content area, scaling, and scaling to fit are mutually exclusive
650
+ # See http://tdg.docbook.org/tdg/4.5/imagedata-x.html#d0e79635
651
+ if attributes.key? 'scaledwidth'
652
+ %( width="#{attributes['scaledwidth']}")
653
+ elsif attributes.key? 'scale'
654
+ # QUESTION should we set the viewport using width and depth? (the scaled image would be contained within this box)
655
+ #width_attribute = (attributes.key? 'width') ? %( width="#{attributes['width']}") : ''
656
+ #depth_attribute = (attributes.key? 'height') ? %( depth="#{attributes['height']}") : ''
657
+ %( scale="#{attributes['scale']}")
658
+ else
659
+ width_attribute = (attributes.key? 'width') ? %( contentwidth="#{attributes['width']}") : ''
660
+ depth_attribute = (attributes.key? 'height') ? %( contentdepth="#{attributes['height']}") : ''
661
+ %(#{width_attribute}#{depth_attribute})
662
+ end
663
+ end
664
+
651
665
  def author_tag doc, author
652
666
  result = []
653
667
  result << '<author>'
@@ -661,7 +675,7 @@ class Converter::DocBook5Converter < Converter::Base
661
675
  result.join LF
662
676
  end
663
677
 
664
- def document_info_tag doc
678
+ def document_info_tag doc, abstract
665
679
  result = ['<info>']
666
680
  unless doc.notitle
667
681
  if (title = doc.doctitle partition: true, use_fallback: true).subtitle?
@@ -715,11 +729,37 @@ class Converter::DocBook5Converter < Converter::Base
715
729
  result << docinfo_content
716
730
  end
717
731
  end
732
+ if abstract
733
+ abstract.set_option 'root'
734
+ result << (convert abstract, abstract.node_name)
735
+ abstract.remove_attr 'root-option'
736
+ end
718
737
  result << '</info>'
719
738
 
720
739
  result.join LF
721
740
  end
722
741
 
742
+ def find_root_abstract doc
743
+ return unless doc.blocks?
744
+ if (first_block = doc.blocks[0]).context == :preamble
745
+ return unless (first_block = first_block.blocks[0])
746
+ elsif first_block.context == :section
747
+ return first_block if first_block.sectname == 'abstract'
748
+ return unless first_block.sectname == 'preface' && (first_block = first_block.blocks[0])
749
+ end
750
+ return first_block if first_block.style == 'abstract' && first_block.context == :open
751
+ end
752
+
753
+ def extract_abstract document, abstract
754
+ parent = abstract.parent
755
+ parent = parent.parent while parent != document && parent.blocks.length == 1
756
+ parent.blocks.delete_at 0
757
+ end
758
+
759
+ def restore_abstract abstract
760
+ abstract.parent.blocks.insert 0, abstract
761
+ end
762
+
723
763
  def get_root_document node
724
764
  while (node = node.document).nested?
725
765
  node = node.parent_document
@@ -742,26 +782,18 @@ class Converter::DocBook5Converter < Converter::Base
742
782
 
743
783
  def cover_tag doc, face, use_placeholder = false
744
784
  if (cover_image = doc.attr %(#{face}-cover-image))
745
- width_attr = ''
746
- depth_attr = ''
747
785
  if (cover_image.include? ':') && ImageMacroRx =~ cover_image
748
- attrlist = $2
749
- cover_image = doc.image_uri $1
750
- if attrlist
751
- attrs = (AttributeList.new attrlist).parse ['alt', 'width', 'height']
752
- if attrs.key? 'scaledwidth'
753
- # NOTE scalefit="1" is the default in this case
754
- width_attr = %( width="#{attrs['scaledwidth']}")
755
- else
756
- width_attr = %( contentwidth="#{attrs['width']}") if attrs.key? 'width'
757
- depth_attr = %( contentdepth="#{attrs['height']}") if attrs.key? 'height'
758
- end
759
- end
786
+ target, attrlist = $1, $2
787
+ cover_image = doc.image_uri target
788
+ # NOTE scalefit="1" is the default for a cover image
789
+ size_attrs = image_size_attributes (AttributeList.new attrlist).parse %w(alt width height) if attrlist
790
+ else
791
+ size_attrs = ''
760
792
  end
761
793
  %(<cover role="#{face}">
762
794
  <mediaobject>
763
795
  <imageobject>
764
- <imagedata fileref="#{cover_image}"#{width_attr}#{depth_attr}/>
796
+ <imagedata fileref="#{cover_image}"#{size_attrs}/>
765
797
  </imageobject>
766
798
  </mediaobject>
767
799
  </cover>)
@@ -748,7 +748,7 @@ Your browser does not support the audio tag.
748
748
  def convert_open node
749
749
  if (style = node.style) == 'abstract'
750
750
  if node.parent == node.document && node.document.doctype == 'book'
751
- logger.warn 'abstract block cannot be used in a document without a title when doctype is book. Excluding block content.'
751
+ logger.warn 'abstract block cannot be used in a document without a doctitle when doctype is book. Excluding block content.'
752
752
  ''
753
753
  else
754
754
  id_attr = node.id ? %( id="#{node.id}") : ''
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module Asciidoctor
3
- # A built-in {Converter} implementation that generates the man page (troff) format.
3
+ # A built-in {Converter} implementation that generates the man page (groff) format.
4
4
  #
5
5
  # The output of this converter adheres to the man definition as defined by
6
6
  # groff and uses the manpage output of the DocBook toolchain as a foundation.
@@ -432,7 +432,7 @@ allbox tab(:);'
432
432
  when :literal
433
433
  cell_content = %(.nf#{LF}#{manify cell.text, whitespace: :preserve}#{LF}.fi)
434
434
  else
435
- cell_content = manify cell.content.join, whitespace: :normalize
435
+ cell_content = cell.content.map {|p| manify p, whitespace: :normalize }.join %(#{LF}.sp#{LF})
436
436
  end
437
437
  row_text[row_index] << %(#{cell_content}#{LF})
438
438
  else # tsec == :head || tsec == :foot
@@ -476,21 +476,14 @@ allbox tab(:);'
476
476
  end unless rows.empty?
477
477
  end
478
478
 
479
- #row_header.each do |row|
480
- # result << LF
481
- # row.each_with_index do |cell, i|
482
- # result << (cell.join ' ')
483
- # result << ' ' if row.size > i + 1
484
- # end
485
- #end
486
- # FIXME temporary fix to get basic table to display
487
- result << LF
488
- result << ('lt ' * row_header[0].size).chop
489
-
490
- result << %(.#{LF})
491
- row_text.each do |row|
492
- result << row.join
479
+ if node.has_header_option && (header_row_text = row_text[0])
480
+ result << %(#{LF}#{row_header[0].join ' '}.)
481
+ result << %(#{LF}#{header_row_text.join})
482
+ result << '.T&'
483
+ row_text = row_text.slice 1, row_text.length
493
484
  end
485
+ result << %(#{LF}#{row_header[0].map { 'lt' }.join ' '}.#{LF})
486
+ row_text.each {|row| result << row.join }
494
487
  result << %(.TE#{LF}.sp)
495
488
  result.join
496
489
  end
@@ -712,40 +705,38 @@ allbox tab(:);'
712
705
  else
713
706
  str = str.tr_s WHITESPACE, ' '
714
707
  end
715
- str = str
716
- .gsub(LiteralBackslashRx) { $1 ? $& : '\\(rs' } # literal backslash (not a troff escape sequence)
717
- .gsub(EllipsisCharRefRx, '...') # horizontal ellipsis
718
- .gsub(LeadingPeriodRx, '\\\&.') # leading . is used in troff for macro call or other formatting; replace with \&.
719
- .gsub(EscapedMacroRx) do # drop orphaned \c escape lines, unescape troff macro, quote adjacent character, isolate macro line
720
- (rest = $3.lstrip).empty? ? %(.#{$1}"#{$2}") : %(.#{$1}"#{$2.rstrip}"#{LF}#{rest})
721
- end
722
- .gsub('-', '\-')
723
- .gsub('&lt;', '<')
724
- .gsub('&gt;', '>')
725
- .gsub('&#43;', '+') # plus sign; alternately could use \c(pl
726
- .gsub('&#160;', '\~') # non-breaking space
727
- .gsub('&#169;', '\(co') # copyright sign
728
- .gsub('&#174;', '\(rg') # registered sign
729
- .gsub('&#8482;', '\(tm') # trademark sign
730
- .gsub('&#176;', '\(de') # degree sign
731
- .gsub('&#8201;', ' ') # thin space
732
- .gsub('&#8211;', '\(en') # en dash
733
- .gsub(EmDashCharRefRx, '\(em') # em dash
734
- .gsub('&#8216;', '\(oq') # left single quotation mark
735
- .gsub('&#8217;', '\(cq') # right single quotation mark
736
- .gsub('&#8220;', '\(lq') # left double quotation mark
737
- .gsub('&#8221;', '\(rq') # right double quotation mark
738
- .gsub('&#8592;', '\(<-') # leftwards arrow
739
- .gsub('&#8594;', '\(->') # rightwards arrow
740
- .gsub('&#8656;', '\(lA') # leftwards double arrow
741
- .gsub('&#8658;', '\(rA') # rightwards double arrow
742
- .gsub('&#8203;', '\:') # zero width space
743
- .gsub('&amp;', '&') # literal ampersand (NOTE must take place after any other replacement that includes &)
744
- .gsub('\'', '\*(Aq') # apostrophe / neutral single quote
745
- .gsub(MockMacroRx, '\1') # mock boundary
746
- .gsub(ESC_BS, '\\') # unescape troff backslash (NOTE update if more escapes are added)
747
- .gsub(ESC_FS, '.') # unescape full stop in troff commands (NOTE must take place after gsub(LeadingPeriodRx))
748
- .rstrip # strip trailing space
708
+ str = str.
709
+ gsub(LiteralBackslashRx) { $1 ? $& : '\\(rs' }. # literal backslash (not a troff escape sequence)
710
+ gsub(EllipsisCharRefRx, '...'). # horizontal ellipsis
711
+ gsub(LeadingPeriodRx, '\\\&.'). # leading . is used in troff for macro call or other formatting; replace with \&.
712
+ gsub(EscapedMacroRx) { (rest = $3.lstrip).empty? ? %(.#{$1}"#{$2}") : %(.#{$1}"#{$2.rstrip}"#{LF}#{rest}) }. # drop orphaned \c escape lines, unescape troff macro, quote adjacent character, isolate macro line
713
+ gsub('-', '\-').
714
+ gsub('&lt;', '<').
715
+ gsub('&gt;', '>').
716
+ gsub('&#43;', '+'). # plus sign; alternately could use \c(pl
717
+ gsub('&#160;', '\~'). # non-breaking space
718
+ gsub('&#169;', '\(co'). # copyright sign
719
+ gsub('&#174;', '\(rg'). # registered sign
720
+ gsub('&#8482;', '\(tm'). # trademark sign
721
+ gsub('&#176;', '\(de'). # degree sign
722
+ gsub('&#8201;', ' '). # thin space
723
+ gsub('&#8211;', '\(en'). # en dash
724
+ gsub(EmDashCharRefRx, '\(em'). # em dash
725
+ gsub('&#8216;', '\(oq'). # left single quotation mark
726
+ gsub('&#8217;', '\(cq'). # right single quotation mark
727
+ gsub('&#8220;', '\(lq'). # left double quotation mark
728
+ gsub('&#8221;', '\(rq'). # right double quotation mark
729
+ gsub('&#8592;', '\(<-'). # leftwards arrow
730
+ gsub('&#8594;', '\(->'). # rightwards arrow
731
+ gsub('&#8656;', '\(lA'). # leftwards double arrow
732
+ gsub('&#8658;', '\(rA'). # rightwards double arrow
733
+ gsub('&#8203;', '\:'). # zero width space
734
+ gsub('&amp;', '&'). # literal ampersand (NOTE must take place after any other replacement that includes &)
735
+ gsub('\'', '\*(Aq'). # apostrophe / neutral single quote
736
+ gsub(MockMacroRx, '\1'). # mock boundary
737
+ gsub(ESC_BS, '\\'). # unescape troff backslash (NOTE update if more escapes are added)
738
+ gsub(ESC_FS, '.'). # unescape full stop in troff commands (NOTE must take place after gsub(LeadingPeriodRx))
739
+ rstrip # strip trailing space
749
740
  opts[:append_newline] ? %(#{str}#{LF}) : str
750
741
  end
751
742
 
@@ -40,6 +40,7 @@ class MemoryLogger < ::Logger
40
40
  attr_reader :messages
41
41
 
42
42
  def initialize
43
+ super nil
43
44
  self.level = WARN
44
45
  @messages = []
45
46
  end
@@ -67,6 +68,7 @@ class NullLogger < ::Logger
67
68
  attr_reader :max_severity
68
69
 
69
70
  def initialize
71
+ super nil
70
72
  self.level = WARN
71
73
  end
72
74
 
@@ -43,6 +43,12 @@ class Parser
43
43
 
44
44
  AuthorKeys = ['author', 'authorinitials', 'firstname', 'middlename', 'lastname', 'email']
45
45
 
46
+ ListContinuationMarker = ::Module.new
47
+
48
+ ListContinuationPlaceholder = ::String.new.extend ListContinuationMarker
49
+
50
+ ListContinuationString = (::String.new LIST_CONTINUATION).extend ListContinuationMarker
51
+
46
52
  # Internal: A Hash mapping horizontal alignment abbreviations to alignments
47
53
  # that can be applied to a table cell (or to all cells in a column)
48
54
  TableCellHorzAlignments = {
@@ -1420,17 +1426,18 @@ class Parser
1420
1426
  # the termination of the list
1421
1427
  break if is_sibling_list_item?(this_line, list_type, sibling_trait)
1422
1428
 
1429
+ this_line = ListContinuationString if this_line == LIST_CONTINUATION
1423
1430
  prev_line = buffer.empty? ? nil : buffer[-1]
1424
1431
 
1425
- if prev_line == LIST_CONTINUATION
1432
+ if ListContinuationMarker === prev_line
1426
1433
  if continuation == :inactive
1427
1434
  continuation = :active
1428
1435
  has_text = true
1429
- buffer[-1] = '' unless within_nested_list
1436
+ buffer[-1] = ListContinuationPlaceholder unless within_nested_list
1430
1437
  end
1431
1438
 
1432
1439
  # dealing with adjacent list continuations (which is really a syntax error)
1433
- if this_line == LIST_CONTINUATION
1440
+ if ListContinuationMarker === this_line
1434
1441
  if continuation != :frozen
1435
1442
  continuation = :frozen
1436
1443
  buffer << this_line
@@ -1489,7 +1496,7 @@ class Parser
1489
1496
  (ch0 == '[' && (BlockAttributeLineRx.match? this_line)) || (ch0 == ':' && (AttributeEntryRx.match? this_line))
1490
1497
  buffer << this_line
1491
1498
  else
1492
- if (nested_list_type = (within_nested_list ? [:dlist] : NESTABLE_LIST_CONTEXTS).find {|ctx| ListRxMap[ctx].match? this_line })
1499
+ if (nested_list_type = (within_nested_list ? [:dlist] : NESTABLE_LIST_CONTEXTS).find {|ctx| ListRxMap[ctx] =~ this_line })
1493
1500
  within_nested_list = true
1494
1501
  if nested_list_type == :dlist && $3.nil_or_empty?
1495
1502
  # get greedy again
@@ -1510,7 +1517,7 @@ class Parser
1510
1517
 
1511
1518
  if this_line == LIST_CONTINUATION
1512
1519
  detached_continuation = buffer.size
1513
- buffer << this_line
1520
+ buffer << ListContinuationString
1514
1521
  elsif has_text # has_text only relevant for dlist, which is more greedy until it has text for an item; has_text is always true for all other lists
1515
1522
  # in this block, we have to see whether we stay in the list
1516
1523
  # TODO any way to combine this with the check after skipping blank lines?
@@ -1543,6 +1550,9 @@ class Parser
1543
1550
  buffer << this_line
1544
1551
  has_text = true
1545
1552
  end
1553
+ elsif ListContinuationMarker === this_line
1554
+ has_text = true
1555
+ buffer << this_line
1546
1556
  else
1547
1557
  has_text = true unless this_line.empty?
1548
1558
  if (nested_list_type = (within_nested_list ? [:dlist] : NESTABLE_LIST_CONTEXTS).find {|ctx| ListRxMap[ctx] =~ this_line })
@@ -1559,16 +1569,17 @@ class Parser
1559
1569
 
1560
1570
  reader.unshift_line this_line if this_line
1561
1571
 
1562
- buffer[detached_continuation] = '' if detached_continuation
1572
+ buffer[detached_continuation] = ListContinuationPlaceholder if detached_continuation
1563
1573
 
1564
1574
  until buffer.empty?
1575
+ # drop optional trailing continuation
1576
+ if ListContinuationMarker === (last_line = buffer[-1])
1577
+ buffer.pop
1578
+ break
1565
1579
  # strip trailing blank lines to prevent empty blocks
1566
- if (last_line = buffer[-1]).empty?
1580
+ elsif last_line.empty?
1567
1581
  buffer.pop
1568
1582
  else
1569
- # drop optional trailing continuation
1570
- # (a blank line would have served the same purpose in the document)
1571
- buffer.pop if last_line == LIST_CONTINUATION
1572
1583
  break
1573
1584
  end
1574
1585
  end
@@ -1039,6 +1039,7 @@ class PreprocessorReader < Reader
1039
1039
  # if running in SafeMode::SECURE or greater, don't process this directive
1040
1040
  # however, be friendly and at least make it a link to the source document
1041
1041
  elsif doc.safe >= SafeMode::SECURE
1042
+ expanded_target = %(pass:c[#{expanded_target}]) if expanded_target.include? ' '
1042
1043
  # FIXME we don't want to use a link macro if we are in a verbatim context
1043
1044
  replace_next_line %(link:#{expanded_target}[role=include])
1044
1045
  elsif @maxdepth
@@ -1238,7 +1239,10 @@ class PreprocessorReader < Reader
1238
1239
  def resolve_include_path target, attrlist, attributes
1239
1240
  doc = @document
1240
1241
  if (Helpers.uriish? target) || (::String === @dir ? nil : (target = %(#{@dir}/#{target})))
1241
- return replace_next_line %(link:#{target}[role=include]) unless doc.attr? 'allow-uri-read'
1242
+ unless doc.attr? 'allow-uri-read'
1243
+ target = %(pass:c[#{target}]) if target.include? ' '
1244
+ return replace_next_line %(link:#{target}[role=include])
1245
+ end
1242
1246
  if doc.attr? 'cache-uri'
1243
1247
  # caching requires the open-uri-cached gem to be installed
1244
1248
  # processing will be automatically aborted if these libraries can't be opened
@@ -513,12 +513,12 @@ module Asciidoctor
513
513
  #
514
514
  # https://github.com
515
515
  # https://github.com[GitHub]
516
- # <https://github.com>
516
+ # <https://github.com> <= angle brackets not included in autolink
517
517
  # link:https://github.com[]
518
518
  # "https://github.com[]"
519
519
  # (https://github.com) <= parenthesis not included in autolink
520
520
  #
521
- InlineLinkRx = %r((^|link:|#{CG_BLANK}|&lt;|[>\(\)\[\];"'])(\\?(?:https?|file|ftp|irc)://)(?:([^\s\[\]]+)\[(|#{CC_ALL}*?[^\\])\]|([^\s\[\]<]*([^\s,.?!\[\]<\)]))))m
521
+ InlineLinkRx = %r((^|link:|#{CG_BLANK}|\\?&lt;()|[>\(\)\[\];"'])(\\?(?:https?|file|ftp|irc)://)(?:([^\s\[\]]+)\[(|#{CC_ALL}*?[^\\])\]|\2([^\s]*?)&gt;|([^\s\[\]<]*([^\s,.?!\[\]<\)]))))m
522
522
 
523
523
  # Match a link or e-mail inline macro.
524
524
  #
@@ -445,7 +445,14 @@ module Substitutors
445
445
  # indexterm:[Tigers,Big cats]
446
446
  if (attrlist = normalize_text $2, true, true).include? '='
447
447
  if (primary = (attrs = (AttributeList.new attrlist, self).parse)[1])
448
- attrs['terms'] = [primary]
448
+ terms = [primary]
449
+ if (secondary = attrs[2])
450
+ terms << secondary
451
+ if (tertiary = attrs[3])
452
+ terms << tertiary
453
+ end
454
+ end
455
+ attrs['terms'] = terms
449
456
  if (see_also = attrs['see-also'])
450
457
  attrs['see-also'] = (see_also.include? ',') ? (see_also.split ',').map {|it| it.lstrip } : [see_also]
451
458
  end
@@ -524,97 +531,101 @@ module Substitutors
524
531
  end
525
532
 
526
533
  if found_colon && (text.include? '://')
527
- # inline urls, target[text] (optionally prefixed with link: and optionally surrounded by <>)
534
+ # inline urls, target[text] (optionally prefixed with link: or enclosed in <>)
528
535
  text = text.gsub InlineLinkRx do
529
- if (target = $2 + ($3 || $5)).start_with? RS
530
- # honor the escape
531
- next ($&.slice 0, (rs_idx = $1.length)) + ($&.slice rs_idx + 1, $&.length)
532
- end
533
-
534
- prefix, suffix = $1, ''
535
- # NOTE if $4 is set, we're looking at a formal macro (e.g., https://example.org[])
536
- if $4
537
- prefix = '' if prefix == 'link:'
538
- link_text = nil if (link_text = $4).empty?
536
+ if $2 && !$5
537
+ # honor the escapes
538
+ next $&.slice 1, $&.length if $1.start_with? RS
539
+ next %(#{$1}#{$&.slice $1.length + 1, $&.length}) if $3.start_with? RS
540
+ target = $3 + $6
541
+ next $& if target == $3
542
+ doc.register :links, target
543
+ link_text = (doc_attrs.key? 'hide-uri-scheme') ? (target.sub UriSniffRx, '') : target
544
+ (Inline.new self, :anchor, link_text, type: :link, target: target, attributes: { 'role' => 'bare' }).convert
539
545
  else
540
- # invalid macro syntax (link: prefix w/o trailing square brackets or enclosed in double quotes)
541
- # FIXME we probably shouldn't even get here when the link: prefix is present; the regex is doing too much
542
- case prefix
543
- when 'link:', ?", ?'
544
- next $&
545
- end
546
- case $6
547
- when ';'
548
- if (prefix.start_with? '&lt;') && (target.end_with? '&gt;')
549
- # move surrounding <> out of URL
550
- prefix = prefix.slice 4, prefix.length
551
- target = target.slice 0, target.length - 4
552
- elsif (target = target.chop).end_with? ')'
553
- # move trailing ); out of URL
554
- target = target.chop
555
- suffix = ');'
556
- else
557
- # move trailing ; out of URL
558
- suffix = ';'
546
+ # honor the escape
547
+ next %(#{$1}#{$&.slice $1.length + 1, $&.length}) if $3.start_with? RS
548
+ prefix, target, suffix = $1, $3 + ($4 || $7), ''
549
+ # NOTE if $5 is set (the attrlist), we're looking at a formal macro (e.g., https://example.org[])
550
+ if $5
551
+ prefix = '' if prefix == 'link:'
552
+ link_text = nil if (link_text = $5).empty?
553
+ else
554
+ case prefix
555
+ # invalid macro syntax (link: prefix w/o trailing square brackets or URL enclosed in quotes)
556
+ # FIXME we probably shouldn't even get here when the link: prefix is present; the regex is doing too much
557
+ when 'link:', ?", ?'
558
+ next $&
559
559
  end
560
- # NOTE handle case when modified target is a URI scheme (e.g., http://)
561
- next $& if target.end_with? '://'
562
- when ':'
563
- if (target = target.chop).end_with? ')'
564
- # move trailing ): out of URL
565
- target = target.chop
566
- suffix = '):'
567
- else
568
- # move trailing : out of URL
569
- suffix = ':'
560
+ case $8
561
+ when ';'
562
+ if (target = target.chop).end_with? ')'
563
+ # move trailing ); out of URL
564
+ target = target.chop
565
+ suffix = ');'
566
+ else
567
+ # move trailing ; out of URL
568
+ suffix = ';'
569
+ end
570
+ # NOTE handle case when modified target is a bare URI scheme (e.g., http://)
571
+ next $& if target == $3
572
+ when ':'
573
+ if (target = target.chop).end_with? ')'
574
+ # move trailing ): out of URL
575
+ target = target.chop
576
+ suffix = '):'
577
+ else
578
+ # move trailing : out of URL
579
+ suffix = ':'
580
+ end
581
+ # NOTE handle case when modified target is a bare URI scheme (e.g., http://)
582
+ next $& if target == $3
570
583
  end
571
- # NOTE handle case when modified target is a URI scheme (e.g., http://)
572
- next $& if target.end_with? '://'
573
584
  end
574
- end
575
585
 
576
- attrs, link_opts = nil, { type: :link }
586
+ link_opts = { type: :link }
577
587
 
578
- if link_text
579
- new_link_text = link_text = link_text.gsub ESC_R_SB, R_SB if link_text.include? R_SB
580
- if !doc.compat_mode && (link_text.include? '=')
581
- # NOTE if an equals sign (=) is present, extract attributes from link text
582
- link_text, attrs = extract_attributes_from_text link_text, ''
583
- new_link_text = link_text
584
- link_opts[:id] = attrs['id']
585
- end
588
+ if link_text
589
+ new_link_text = link_text = link_text.gsub ESC_R_SB, R_SB if link_text.include? R_SB
590
+ if !doc.compat_mode && (link_text.include? '=')
591
+ # NOTE if an equals sign (=) is present, extract attributes from link text
592
+ link_text, attrs = extract_attributes_from_text link_text, ''
593
+ new_link_text = link_text
594
+ link_opts[:id] = attrs['id']
595
+ end
586
596
 
587
- if link_text.end_with? '^'
588
- new_link_text = link_text = link_text.chop
589
- if attrs
590
- attrs['window'] ||= '_blank'
591
- else
592
- attrs = { 'window' => '_blank' }
597
+ if link_text.end_with? '^'
598
+ new_link_text = link_text = link_text.chop
599
+ if attrs
600
+ attrs['window'] ||= '_blank'
601
+ else
602
+ attrs = { 'window' => '_blank' }
603
+ end
593
604
  end
594
- end
595
605
 
596
- if new_link_text && new_link_text.empty?
597
- # NOTE it's not possible for the URI scheme to be bare in this case
606
+ if new_link_text && new_link_text.empty?
607
+ # NOTE the modified target will not be a bare URI scheme (e.g., http://) in this case
608
+ link_text = (doc_attrs.key? 'hide-uri-scheme') ? (target.sub UriSniffRx, '') : target
609
+ bare = true
610
+ end
611
+ else
612
+ # NOTE the modified target will not be a bare URI scheme (e.g., http://) in this case
598
613
  link_text = (doc_attrs.key? 'hide-uri-scheme') ? (target.sub UriSniffRx, '') : target
599
614
  bare = true
600
615
  end
601
- else
602
- # NOTE it's not possible for the URI scheme to be bare in this case
603
- link_text = (doc_attrs.key? 'hide-uri-scheme') ? (target.sub UriSniffRx, '') : target
604
- bare = true
605
- end
606
616
 
607
- if bare
608
- if attrs
609
- attrs['role'] = (attrs.key? 'role') ? %(bare #{attrs['role']}) : 'bare'
610
- else
611
- attrs = { 'role' => 'bare' }
617
+ if bare
618
+ if attrs
619
+ attrs['role'] = (attrs.key? 'role') ? %(bare #{attrs['role']}) : 'bare'
620
+ else
621
+ attrs = { 'role' => 'bare' }
622
+ end
612
623
  end
613
- end
614
624
 
615
- doc.register :links, (link_opts[:target] = target)
616
- link_opts[:attributes] = attrs if attrs
617
- %(#{prefix}#{(Inline.new self, :anchor, link_text, link_opts).convert}#{suffix})
625
+ doc.register :links, (link_opts[:target] = target)
626
+ link_opts[:attributes] = attrs if attrs
627
+ %(#{prefix}#{(Inline.new self, :anchor, link_text, link_opts).convert}#{suffix})
628
+ end
618
629
  end
619
630
  end
620
631
 
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Asciidoctor
3
- VERSION = '2.0.20'
3
+ VERSION = '2.0.21'
4
4
  end
data/lib/asciidoctor.rb CHANGED
@@ -215,7 +215,7 @@ module Asciidoctor
215
215
  URI_READ_MODE = FILE_READ_MODE
216
216
 
217
217
  # The mode to use when opening a file for writing
218
- FILE_WRITE_MODE = RUBY_ENGINE_OPAL ? 'w' : 'w:utf-8'
218
+ FILE_WRITE_MODE = RUBY_ENGINE_OPAL ? 'w' : 'wb:utf-8'
219
219
 
220
220
  # The default document type
221
221
  # Can influence markup generated by the converters
data/man/asciidoctor.1 CHANGED
@@ -1,13 +1,13 @@
1
1
  '\" t
2
2
  .\" Title: asciidoctor
3
3
  .\" Author: Dan Allen, Sarah White
4
- .\" Generator: Asciidoctor 2.0.19
4
+ .\" Generator: Asciidoctor 2.0.20
5
5
  .\" Date: 2018-03-20
6
6
  .\" Manual: Asciidoctor Manual
7
- .\" Source: Asciidoctor 2.0.20
7
+ .\" Source: Asciidoctor 2.0.21
8
8
  .\" Language: English
9
9
  .\"
10
- .TH "ASCIIDOCTOR" "1" "2018-03-20" "Asciidoctor 2.0.20" "Asciidoctor Manual"
10
+ .TH "ASCIIDOCTOR" "1" "2018-03-20" "Asciidoctor 2.0.21" "Asciidoctor Manual"
11
11
  .ie \n(.g .ds Aq \(aq
12
12
  .el .ds Aq '
13
13
  .ss \n[.ss] 0
data/man/asciidoctor.adoc CHANGED
@@ -1,7 +1,7 @@
1
1
  = asciidoctor(1)
2
2
  Dan Allen; Sarah White
3
3
  :doctype: manpage
4
- :release-version: 2.0.20
4
+ :release-version: 2.0.21
5
5
  :man manual: Asciidoctor Manual
6
6
  :man source: Asciidoctor {release-version}
7
7
  ifdef::backend-manpage[:!author:]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoctor
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.20
4
+ version: 2.0.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Allen
@@ -272,7 +272,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
272
272
  - !ruby/object:Gem::Version
273
273
  version: '0'
274
274
  requirements: []
275
- rubygems_version: 3.4.10
275
+ rubygems_version: 3.5.3
276
276
  signing_key:
277
277
  specification_version: 4
278
278
  summary: An implementation of the AsciiDoc text processor and publishing toolchain