asciidoctor 1.5.5 → 1.5.6
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.
Potentially problematic release.
This version of asciidoctor might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +216 -1
- data/CONTRIBUTING.adoc +2 -2
- data/Gemfile +20 -1
- data/LICENSE.adoc +1 -1
- data/README-fr.adoc +4 -3
- data/README-jp.adoc +11 -10
- data/README-zh_CN.adoc +4 -3
- data/README.adoc +17 -202
- data/Rakefile +41 -25
- data/asciidoctor.gemspec +9 -10
- data/data/locale/attributes.adoc +216 -34
- data/data/stylesheets/asciidoctor-default.css +23 -16
- data/features/step_definitions.rb +15 -19
- data/features/xref.feature +584 -20
- data/lib/asciidoctor.rb +292 -278
- data/lib/asciidoctor/abstract_block.rb +155 -94
- data/lib/asciidoctor/abstract_node.rb +108 -94
- data/lib/asciidoctor/attribute_list.rb +30 -22
- data/lib/asciidoctor/block.rb +7 -7
- data/lib/asciidoctor/cli/invoker.rb +47 -34
- data/lib/asciidoctor/cli/options.rb +22 -11
- data/lib/asciidoctor/converter.rb +3 -3
- data/lib/asciidoctor/converter/base.rb +2 -2
- data/lib/asciidoctor/converter/composite.rb +1 -1
- data/lib/asciidoctor/converter/docbook45.rb +2 -2
- data/lib/asciidoctor/converter/docbook5.rb +132 -87
- data/lib/asciidoctor/converter/factory.rb +0 -1
- data/lib/asciidoctor/converter/html5.rb +116 -98
- data/lib/asciidoctor/converter/manpage.rb +51 -52
- data/lib/asciidoctor/converter/template.rb +47 -36
- data/lib/asciidoctor/core_ext.rb +8 -2
- data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +4 -0
- data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +6 -0
- data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +5 -0
- data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +1 -1
- data/lib/asciidoctor/core_ext/1.8.7/string/{limit.rb → limit_bytesize.rb} +7 -6
- data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +6 -0
- data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +1 -1
- data/lib/asciidoctor/core_ext/nil_or_empty.rb +5 -5
- data/lib/asciidoctor/core_ext/regexp/is_match.rb +3 -0
- data/lib/asciidoctor/core_ext/string/{limit.rb → limit_bytesize.rb} +2 -2
- data/lib/asciidoctor/document.rb +216 -213
- data/lib/asciidoctor/extensions.rb +318 -185
- data/lib/asciidoctor/helpers.rb +35 -35
- data/lib/asciidoctor/inline.rb +32 -1
- data/lib/asciidoctor/list.rb +22 -6
- data/lib/asciidoctor/parser.rb +1008 -1038
- data/lib/asciidoctor/path_resolver.rb +46 -50
- data/lib/asciidoctor/reader.rb +275 -251
- data/lib/asciidoctor/section.rb +86 -58
- data/lib/asciidoctor/stylesheets.rb +6 -6
- data/lib/asciidoctor/substitutors.rb +567 -649
- data/lib/asciidoctor/table.rb +163 -108
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +18 -16
- data/man/asciidoctor.adoc +15 -13
- data/test/attributes_test.rb +138 -22
- data/test/blocks_test.rb +377 -97
- data/test/converter_test.rb +13 -0
- data/test/document_test.rb +244 -34
- data/test/extensions_test.rb +409 -42
- data/test/fixtures/asciidoc_index.txt +521 -0
- data/test/fixtures/basic-docinfo-footer.html +6 -0
- data/test/fixtures/basic-docinfo-footer.xml +8 -0
- data/test/fixtures/basic-docinfo.html +1 -0
- data/test/fixtures/basic-docinfo.xml +4 -0
- data/test/fixtures/basic.asciidoc +5 -0
- data/test/fixtures/chapter-a.adoc +3 -0
- data/test/fixtures/child-include.adoc +5 -0
- data/test/fixtures/circle.svg +9 -0
- data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +6 -0
- data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +6 -0
- data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +1 -0
- data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +3 -0
- data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +5 -0
- data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +6 -0
- data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +3 -0
- data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +5 -0
- data/test/fixtures/custom-docinfodir/basic-docinfo.html +1 -0
- data/test/fixtures/custom-docinfodir/docinfo.html +1 -0
- data/test/fixtures/docinfo-footer.html +1 -0
- data/test/fixtures/docinfo-footer.xml +9 -0
- data/test/fixtures/docinfo.html +1 -0
- data/test/fixtures/docinfo.xml +3 -0
- data/test/fixtures/dot.gif +0 -0
- data/test/fixtures/encoding.asciidoc +13 -0
- data/test/fixtures/grandchild-include.adoc +3 -0
- data/test/fixtures/hello-asciidoctor.pdf +69 -0
- data/test/fixtures/include-file.asciidoc +24 -0
- data/test/fixtures/include-file.ml +3 -0
- data/test/fixtures/include-file.xml +5 -0
- data/test/fixtures/master.adoc +5 -0
- data/test/fixtures/mismatched-end-tag.adoc +7 -0
- data/test/fixtures/parent-include-restricted.adoc +5 -0
- data/test/fixtures/parent-include.adoc +5 -0
- data/test/fixtures/sample.asciidoc +26 -0
- data/test/fixtures/stylesheets/custom.css +3 -0
- data/test/fixtures/subs-docinfo.html +2 -0
- data/test/fixtures/subs.adoc +7 -0
- data/test/fixtures/tagged-class-enclosed.rb +26 -0
- data/test/fixtures/tagged-class.rb +23 -0
- data/test/fixtures/tip.gif +0 -0
- data/test/invoker_test.rb +82 -4
- data/test/links_test.rb +312 -37
- data/test/lists_test.rb +204 -25
- data/test/manpage_test.rb +191 -4
- data/test/options_test.rb +18 -1
- data/test/paragraphs_test.rb +32 -7
- data/test/parser_test.rb +150 -30
- data/test/paths_test.rb +47 -13
- data/test/preamble_test.rb +1 -1
- data/test/reader_test.rb +366 -126
- data/test/sections_test.rb +203 -56
- data/test/substitutions_test.rb +339 -131
- data/test/tables_test.rb +315 -15
- data/test/test_helper.rb +400 -0
- data/test/text_test.rb +5 -5
- metadata +110 -22
| @@ -22,38 +22,31 @@ module Asciidoctor | |
| 22 22 | 
             
            #    => {'style' => 'quote', 'attribution' => 'Famous Person', 'citetitle' => 'Famous Book (2001)'}
         | 
| 23 23 | 
             
            #
         | 
| 24 24 | 
             
            class AttributeList
         | 
| 25 | 
            -
             | 
| 26 | 
            -
              # FIXME Opal not inheriting constants from parent scope
         | 
| 27 | 
            -
              # NOTE can't use ::RUBY_ENGINE_OPAL here either
         | 
| 28 | 
            -
              if ::RUBY_ENGINE == 'opal'
         | 
| 29 | 
            -
                CG_BLANK = '[ \\t]'
         | 
| 30 | 
            -
                CC_WORD  = 'a-zA-Z0-9_'
         | 
| 31 | 
            -
                CG_WORD  = '[a-zA-Z0-9_]'
         | 
| 32 | 
            -
              end
         | 
| 25 | 
            +
              BACKSLASH = '\\'
         | 
| 33 26 |  | 
| 34 27 | 
             
              # Public: Regular expressions for detecting the boundary of a value
         | 
| 35 28 | 
             
              BoundaryRxs = {
         | 
| 36 29 | 
             
                '"' => /.*?[^\\](?=")/,
         | 
| 37 30 | 
             
                '\'' => /.*?[^\\](?=')/,
         | 
| 38 | 
            -
                ',' => /.*?( | 
| 31 | 
            +
                ',' => /.*?(?=[ \t]*(,|$))/
         | 
| 39 32 | 
             
              }
         | 
| 40 33 |  | 
| 41 34 | 
             
              # Public: Regular expressions for unescaping quoted characters
         | 
| 42 | 
            -
               | 
| 43 | 
            -
                '"' =>  | 
| 44 | 
            -
                '\'' =>  | 
| 35 | 
            +
              EscapedQuotes = {
         | 
| 36 | 
            +
                '"' => '\\"',
         | 
| 37 | 
            +
                '\'' => '\\\''
         | 
| 45 38 | 
             
              }
         | 
| 46 39 |  | 
| 47 40 | 
             
              # Public: A regular expression for an attribute name (approx. name token from XML)
         | 
| 48 41 | 
             
              # TODO named attributes cannot contain dash characters
         | 
| 49 42 | 
             
              NameRx = /#{CG_WORD}[#{CC_WORD}\-.]*/
         | 
| 50 43 |  | 
| 51 | 
            -
              BlankRx =  | 
| 44 | 
            +
              BlankRx = /[ \t]+/
         | 
| 52 45 |  | 
| 53 46 | 
             
              # Public: Regular expressions for skipping blanks and delimiters
         | 
| 54 47 | 
             
              SkipRxs = {
         | 
| 55 48 | 
             
                :blank => BlankRx,
         | 
| 56 | 
            -
                ',' =>  | 
| 49 | 
            +
                ',' => /[ \t]*(,|$)/
         | 
| 57 50 | 
             
              }
         | 
| 58 51 |  | 
| 59 52 | 
             
              def initialize source, block = nil, delimiter = ','
         | 
| @@ -162,16 +155,27 @@ class AttributeList | |
| 162 155 | 
             
                  # opts is an alias for options
         | 
| 163 156 | 
             
                  case name
         | 
| 164 157 | 
             
                  when 'options', 'opts'
         | 
| 165 | 
            -
                     | 
| 166 | 
            -
             | 
| 167 | 
            -
             | 
| 168 | 
            -
             | 
| 169 | 
            -
             | 
| 158 | 
            +
                    if value.include? ','
         | 
| 159 | 
            +
                      value = value.delete ' ' if value.include? ' '
         | 
| 160 | 
            +
                      (value.split ',').each {|opt| @attributes[%(#{opt}-option)] = '' unless opt.empty? }
         | 
| 161 | 
            +
                    else
         | 
| 162 | 
            +
                      @attributes[%(#{value = value.strip}-option)] = ''
         | 
| 163 | 
            +
                    end
         | 
| 164 | 
            +
                    @attributes['options'] = value
         | 
| 170 165 | 
             
                  else
         | 
| 171 | 
            -
                     | 
| 166 | 
            +
                    if single_quoted_value && @block
         | 
| 167 | 
            +
                      case name
         | 
| 168 | 
            +
                      when 'title', 'reftext'
         | 
| 169 | 
            +
                        @attributes[name] = value
         | 
| 170 | 
            +
                      else
         | 
| 171 | 
            +
                        @attributes[name] = @block.apply_subs value
         | 
| 172 | 
            +
                      end
         | 
| 173 | 
            +
                    else
         | 
| 174 | 
            +
                      @attributes[name] = value
         | 
| 175 | 
            +
                    end
         | 
| 172 176 | 
             
                  end
         | 
| 173 177 | 
             
                else
         | 
| 174 | 
            -
                  resolved_name = single_quoted_value &&  | 
| 178 | 
            +
                  resolved_name = single_quoted_value && @block ? (@block.apply_subs name) : name
         | 
| 175 179 | 
             
                  if (pos_name = pos_attrs[index])
         | 
| 176 180 | 
             
                    @attributes[pos_name] = resolved_name
         | 
| 177 181 | 
             
                  end
         | 
| @@ -193,7 +197,11 @@ class AttributeList | |
| 193 197 |  | 
| 194 198 | 
             
                if (value = scan_to_quote quote)
         | 
| 195 199 | 
             
                  @scanner.get_byte
         | 
| 196 | 
            -
                  value. | 
| 200 | 
            +
                  if value.include? BACKSLASH
         | 
| 201 | 
            +
                    value.gsub EscapedQuotes[quote], quote
         | 
| 202 | 
            +
                  else
         | 
| 203 | 
            +
                    value
         | 
| 204 | 
            +
                  end
         | 
| 197 205 | 
             
                else
         | 
| 198 206 | 
             
                  %(#{quote}#{scan_to_delimiter})
         | 
| 199 207 | 
             
                end
         | 
    
        data/lib/asciidoctor/block.rb
    CHANGED
    
    | @@ -24,7 +24,7 @@ class Block < AbstractBlock | |
| 24 24 | 
             
              }).default = :simple
         | 
| 25 25 |  | 
| 26 26 | 
             
              # Public: Create alias for context to be consistent w/ AsciiDoc
         | 
| 27 | 
            -
              alias  | 
| 27 | 
            +
              alias blockname context
         | 
| 28 28 |  | 
| 29 29 | 
             
              # Public: Get/Set the original Array content for this block, if applicable
         | 
| 30 30 | 
             
              attr_accessor :lines
         | 
| @@ -74,14 +74,14 @@ class Block < AbstractBlock | |
| 74 74 | 
             
                    lock_in_subs
         | 
| 75 75 | 
             
                  # e.g., :subs => nil
         | 
| 76 76 | 
             
                  else
         | 
| 77 | 
            -
                    @subs  | 
| 77 | 
            +
                    # NOTE @subs is initialized as empty array by super constructor
         | 
| 78 78 | 
             
                    # prevent subs from being resolved
         | 
| 79 79 | 
             
                    @default_subs = []
         | 
| 80 80 | 
             
                    @attributes.delete 'subs'
         | 
| 81 81 | 
             
                  end
         | 
| 82 82 | 
             
                # defer subs resolution; subs attribute is honored
         | 
| 83 83 | 
             
                else
         | 
| 84 | 
            -
                  @subs  | 
| 84 | 
            +
                  # NOTE @subs is initialized as empty array by super constructor
         | 
| 85 85 | 
             
                  # QUESTION should we honor :default_subs option (i.e., @default_subs = opts[:default_subs])?
         | 
| 86 86 | 
             
                  @default_subs = nil
         | 
| 87 87 | 
             
                end
         | 
| @@ -109,9 +109,9 @@ class Block < AbstractBlock | |
| 109 109 | 
             
                when :compound
         | 
| 110 110 | 
             
                  super
         | 
| 111 111 | 
             
                when :simple
         | 
| 112 | 
            -
                  apply_subs | 
| 112 | 
            +
                  apply_subs @lines * LF, @subs
         | 
| 113 113 | 
             
                when :verbatim, :raw
         | 
| 114 | 
            -
                  #((apply_subs @lines | 
| 114 | 
            +
                  #((apply_subs @lines * LF, @subs).sub StripLineWiseRx, '\1')
         | 
| 115 115 |  | 
| 116 116 | 
             
                  # QUESTION could we use strip here instead of popping empty lines?
         | 
| 117 117 | 
             
                  # maybe apply_subs can know how to strip whitespace?
         | 
| @@ -121,7 +121,7 @@ class Block < AbstractBlock | |
| 121 121 | 
             
                  else
         | 
| 122 122 | 
             
                    result.shift while (first = result[0]) && first.rstrip.empty?
         | 
| 123 123 | 
             
                    result.pop while (last = result[-1]) && last.rstrip.empty?
         | 
| 124 | 
            -
                    result *  | 
| 124 | 
            +
                    result * LF
         | 
| 125 125 | 
             
                  end
         | 
| 126 126 | 
             
                else
         | 
| 127 127 | 
             
                  warn %(Unknown content model '#{@content_model}' for block: #{to_s}) unless @content_model == :empty
         | 
| @@ -134,7 +134,7 @@ class Block < AbstractBlock | |
| 134 134 | 
             
              # Returns the a String containing the lines joined together or nil if there
         | 
| 135 135 | 
             
              # are no lines
         | 
| 136 136 | 
             
              def source
         | 
| 137 | 
            -
                @lines *  | 
| 137 | 
            +
                @lines * LF
         | 
| 138 138 | 
             
              end
         | 
| 139 139 |  | 
| 140 140 | 
             
              def to_s
         | 
| @@ -7,7 +7,7 @@ module Asciidoctor | |
| 7 7 | 
             
                  attr_reader :documents
         | 
| 8 8 | 
             
                  attr_reader :code
         | 
| 9 9 |  | 
| 10 | 
            -
                  def initialize | 
| 10 | 
            +
                  def initialize *options
         | 
| 11 11 | 
             
                    @documents = []
         | 
| 12 12 | 
             
                    @out = nil
         | 
| 13 13 | 
             
                    @err = nil
         | 
| @@ -33,19 +33,12 @@ module Asciidoctor | |
| 33 33 | 
             
                    return unless @options
         | 
| 34 34 |  | 
| 35 35 | 
             
                    old_verbose = $VERBOSE
         | 
| 36 | 
            -
                    case @options[:verbose]
         | 
| 37 | 
            -
                    when 0
         | 
| 38 | 
            -
                      $VERBOSE = nil
         | 
| 39 | 
            -
                    when 1
         | 
| 40 | 
            -
                      $VERBOSE = false
         | 
| 41 | 
            -
                    when 2
         | 
| 42 | 
            -
                      $VERBOSE = true
         | 
| 43 | 
            -
                    end
         | 
| 44 | 
            -
             | 
| 45 36 | 
             
                    opts = {}
         | 
| 46 37 | 
             
                    infiles = []
         | 
| 47 38 | 
             
                    outfile = nil
         | 
| 48 | 
            -
                     | 
| 39 | 
            +
                    err = @err || $stderr
         | 
| 40 | 
            +
                    show_timings = false
         | 
| 41 | 
            +
             | 
| 49 42 | 
             
                    @options.map do |key, val|
         | 
| 50 43 | 
             
                      case key
         | 
| 51 44 | 
             
                      when :input_files
         | 
| @@ -57,55 +50,75 @@ module Asciidoctor | |
| 57 50 | 
             
                      when :attributes
         | 
| 58 51 | 
             
                        # NOTE processor will dup attributes internally
         | 
| 59 52 | 
             
                        opts[:attributes] = val
         | 
| 53 | 
            +
                      when :timings
         | 
| 54 | 
            +
                        show_timings = val
         | 
| 60 55 | 
             
                      when :trace
         | 
| 61 | 
            -
                        # currently | 
| 56 | 
            +
                        # currently does nothing
         | 
| 57 | 
            +
                      when :verbose
         | 
| 58 | 
            +
                        case val
         | 
| 59 | 
            +
                        when 0
         | 
| 60 | 
            +
                          $VERBOSE = nil
         | 
| 61 | 
            +
                        when 1
         | 
| 62 | 
            +
                          $VERBOSE = false
         | 
| 63 | 
            +
                        when 2
         | 
| 64 | 
            +
                          $VERBOSE = true
         | 
| 65 | 
            +
                        end
         | 
| 62 66 | 
             
                      else
         | 
| 63 67 | 
             
                        opts[key] = val unless val.nil?
         | 
| 64 68 | 
             
                      end
         | 
| 65 69 | 
             
                    end
         | 
| 66 70 |  | 
| 67 | 
            -
                    if infiles.size == 1 | 
| 68 | 
            -
                       | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
                       | 
| 71 | 
            +
                    stdin = if infiles.size == 1
         | 
| 72 | 
            +
                      if (infile0 = infiles[0]) == '-'
         | 
| 73 | 
            +
                        outfile ||= infile0
         | 
| 74 | 
            +
                        true
         | 
| 75 | 
            +
                      elsif ::File.pipe? infile0
         | 
| 76 | 
            +
                        outfile ||= '-'
         | 
| 77 | 
            +
                        nil
         | 
| 78 | 
            +
                      end
         | 
| 72 79 | 
             
                    end
         | 
| 73 80 |  | 
| 74 | 
            -
                     | 
| 75 | 
            -
             | 
| 76 | 
            -
                      tofile = (@out || $stdout)
         | 
| 81 | 
            +
                    tofile = if outfile == '-'
         | 
| 82 | 
            +
                      @out || $stdout
         | 
| 77 83 | 
             
                    elsif outfile
         | 
| 78 | 
            -
                      tofile = outfile
         | 
| 79 84 | 
             
                      opts[:mkdirs] = true
         | 
| 85 | 
            +
                      outfile
         | 
| 80 86 | 
             
                    else
         | 
| 81 | 
            -
                      # automatically calculate outfile based on infile unless to_dir is set
         | 
| 82 | 
            -
                      tofile = nil
         | 
| 83 87 | 
             
                      opts[:mkdirs] = true
         | 
| 88 | 
            +
                      nil # automatically calculate outfile based on infile
         | 
| 84 89 | 
             
                    end
         | 
| 85 90 |  | 
| 86 | 
            -
                     | 
| 87 | 
            -
             | 
| 88 | 
            -
                       | 
| 89 | 
            -
                      input_opts =  | 
| 91 | 
            +
                    if stdin
         | 
| 92 | 
            +
                      # allows use of block to supply stdin, particularly useful for tests
         | 
| 93 | 
            +
                      input = block_given? ? yield : STDIN
         | 
| 94 | 
            +
                      input_opts = opts.merge :to_file => tofile
         | 
| 90 95 | 
             
                      if show_timings
         | 
| 91 | 
            -
                        timings = Timings.new
         | 
| 92 | 
            -
                         | 
| 93 | 
            -
                        timings.print_report((@err || $stderr), ((input.respond_to? :path) ? input.path : '-'))
         | 
| 96 | 
            +
                        @documents << (::Asciidoctor.convert input, (input_opts.merge :timings => (timings = Timings.new)))
         | 
| 97 | 
            +
                        timings.print_report err, '-'
         | 
| 94 98 | 
             
                      else
         | 
| 95 | 
            -
                        @documents << ::Asciidoctor.convert | 
| 99 | 
            +
                        @documents << (::Asciidoctor.convert input, input_opts)
         | 
| 100 | 
            +
                      end
         | 
| 101 | 
            +
                    else
         | 
| 102 | 
            +
                      infiles.each do |infile|
         | 
| 103 | 
            +
                        input_opts = opts.merge :to_file => tofile
         | 
| 104 | 
            +
                        if show_timings
         | 
| 105 | 
            +
                          @documents << (::Asciidoctor.convert_file infile, (input_opts.merge :timings => (timings = Timings.new)))
         | 
| 106 | 
            +
                          timings.print_report err, infile
         | 
| 107 | 
            +
                        else
         | 
| 108 | 
            +
                          @documents << (::Asciidoctor.convert_file infile, input_opts)
         | 
| 109 | 
            +
                        end
         | 
| 96 110 | 
             
                      end
         | 
| 97 111 | 
             
                    end
         | 
| 98 112 | 
             
                  rescue ::Exception => e
         | 
| 99 113 | 
             
                    if ::SignalException === e
         | 
| 100 114 | 
             
                      @code = e.signo
         | 
| 101 115 | 
             
                      # add extra endline if Ctrl+C is used
         | 
| 102 | 
            -
                       | 
| 116 | 
            +
                      err.puts if ::Interrupt === e
         | 
| 103 117 | 
             
                    else
         | 
| 104 118 | 
             
                      @code = (e.respond_to? :status) ? e.status : 1
         | 
| 105 119 | 
             
                      if @options[:trace]
         | 
| 106 120 | 
             
                        raise e
         | 
| 107 121 | 
             
                      else
         | 
| 108 | 
            -
                        err = (@err || $stderr)
         | 
| 109 122 | 
             
                        if ::RuntimeError === e
         | 
| 110 123 | 
             
                          err.puts %(#{e.message} (#{e.class}))
         | 
| 111 124 | 
             
                        else
         | 
| @@ -123,7 +136,7 @@ module Asciidoctor | |
| 123 136 | 
             
                    @documents[0]
         | 
| 124 137 | 
             
                  end
         | 
| 125 138 |  | 
| 126 | 
            -
                  def redirect_streams | 
| 139 | 
            +
                  def redirect_streams out, err = nil
         | 
| 127 140 | 
             
                    @out = out
         | 
| 128 141 | 
             
                    @err = err
         | 
| 129 142 | 
             
                  end
         | 
| @@ -56,14 +56,14 @@ Example: asciidoctor -b html5 source.asciidoc | |
| 56 56 | 
             
                      end
         | 
| 57 57 | 
             
                      opts.on('--safe',
         | 
| 58 58 | 
             
                              'set safe mode level to safe (default: unsafe)',
         | 
| 59 | 
            -
                              'enables include  | 
| 59 | 
            +
                              'enables include directives, but prevents access to ancestor paths of source file',
         | 
| 60 60 | 
             
                              'provided for compatibility with the asciidoc command') do
         | 
| 61 61 | 
             
                        self[:safe] = SafeMode::SAFE
         | 
| 62 62 | 
             
                      end
         | 
| 63 | 
            -
                      opts.on('-S', '--safe-mode SAFE_MODE', (safe_mode_names = SafeMode. | 
| 63 | 
            +
                      opts.on('-S', '--safe-mode SAFE_MODE', (safe_mode_names = SafeMode.names),
         | 
| 64 64 | 
             
                              %(set safe mode level explicitly: [#{safe_mode_names * ', '}] (default: unsafe)),
         | 
| 65 | 
            -
                              'disables potentially dangerous macros in source files, such as include::[]') do | | 
| 66 | 
            -
                        self[:safe] = SafeMode. | 
| 65 | 
            +
                              'disables potentially dangerous macros in source files, such as include::[]') do |name|
         | 
| 66 | 
            +
                        self[:safe] = SafeMode.value_for_name name
         | 
| 67 67 | 
             
                      end
         | 
| 68 68 | 
             
                      opts.on('-s', '--no-header-footer', 'suppress output of header and footer (default: false)') do
         | 
| 69 69 | 
             
                        self[:header_footer] = false
         | 
| @@ -84,7 +84,7 @@ Example: asciidoctor -b html5 source.asciidoc | |
| 84 84 | 
             
                        val = val ? (FORCE_ENCODING ? (val.force_encoding ::Encoding::UTF_8) : val) : ''
         | 
| 85 85 | 
             
                        # move leading ! to end for internal processing
         | 
| 86 86 | 
             
                        #if !val && key.start_with?('!')
         | 
| 87 | 
            -
                        #  key =  | 
| 87 | 
            +
                        #  key = %(#{key[1..-1]}!)
         | 
| 88 88 | 
             
                        #end
         | 
| 89 89 | 
             
                        self[:attributes][key] = val
         | 
| 90 90 | 
             
                      end
         | 
| @@ -93,7 +93,7 @@ Example: asciidoctor -b html5 source.asciidoc | |
| 93 93 | 
             
                        if self[:template_dirs].nil?
         | 
| 94 94 | 
             
                          self[:template_dirs] = [template_dir]
         | 
| 95 95 | 
             
                        elsif ::Array === self[:template_dirs]
         | 
| 96 | 
            -
                          self[:template_dirs] | 
| 96 | 
            +
                          self[:template_dirs] << template_dir
         | 
| 97 97 | 
             
                        else
         | 
| 98 98 | 
             
                          self[:template_dirs] = [self[:template_dirs], template_dir]
         | 
| 99 99 | 
             
                        end
         | 
| @@ -128,8 +128,19 @@ Example: asciidoctor -b html5 source.asciidoc | |
| 128 128 | 
             
                        self[:timings] = true
         | 
| 129 129 | 
             
                      end
         | 
| 130 130 |  | 
| 131 | 
            -
                      opts.on_tail('-h', '--help', ' | 
| 132 | 
            -
             | 
| 131 | 
            +
                      opts.on_tail('-h', '--help [TOPIC]', 'print the help message',
         | 
| 132 | 
            +
                          'show the command usage if TOPIC is not specified (or not recognized)',
         | 
| 133 | 
            +
                          'dump the Asciidoctor man page (in troff/groff format) if TOPIC is manpage') do |topic|
         | 
| 134 | 
            +
                        if topic == 'manpage'
         | 
| 135 | 
            +
                          if ::File.exist?(manpage_path = (::File.join ::Asciidoctor::ROOT_PATH, 'man', 'asciidoctor.1'))
         | 
| 136 | 
            +
                            $stdout.puts(::IO.read manpage_path)
         | 
| 137 | 
            +
                          else
         | 
| 138 | 
            +
                            $stderr.puts 'asciidoctor: FAILED: man page not found; try `man asciidoctor`'
         | 
| 139 | 
            +
                            return 1
         | 
| 140 | 
            +
                          end
         | 
| 141 | 
            +
                        else
         | 
| 142 | 
            +
                          $stdout.puts opts
         | 
| 143 | 
            +
                        end
         | 
| 133 144 | 
             
                        return 0
         | 
| 134 145 | 
             
                      end
         | 
| 135 146 |  | 
| @@ -153,12 +164,12 @@ Example: asciidoctor -b html5 source.asciidoc | |
| 153 164 |  | 
| 154 165 | 
             
                    # shave off the file to process so that options errors appear correctly
         | 
| 155 166 | 
             
                    if args.size == 1 && args[0] == '-'
         | 
| 156 | 
            -
                      infiles | 
| 167 | 
            +
                      infiles << args.pop
         | 
| 157 168 | 
             
                    elsif
         | 
| 158 169 | 
             
                      args.each do |file|
         | 
| 159 170 | 
             
                        if file == '-' || (file.start_with? '-')
         | 
| 160 171 | 
             
                          # warn, but don't panic; we may have enough to proceed, so we won't force a failure
         | 
| 161 | 
            -
                          $stderr.puts  | 
| 172 | 
            +
                          $stderr.puts %(asciidoctor: WARNING: extra arguments detected (unparsed arguments: '#{args * "', '"}') or incorrect usage of stdin)
         | 
| 162 173 | 
             
                        else
         | 
| 163 174 | 
             
                          if ::File.readable? file
         | 
| 164 175 | 
             
                            matches = [file]
         | 
| @@ -179,7 +190,7 @@ Example: asciidoctor -b html5 source.asciidoc | |
| 179 190 | 
             
                    end
         | 
| 180 191 |  | 
| 181 192 | 
             
                    infiles.each do |file|
         | 
| 182 | 
            -
                      unless file == '-' || (::File.file? file)
         | 
| 193 | 
            +
                      unless file == '-' || (::File.file? file) || (::File.pipe? file)
         | 
| 183 194 | 
             
                        if ::File.readable? file
         | 
| 184 195 | 
             
                          $stderr.puts %(asciidoctor: FAILED: input path #{file} is a #{(::File.stat file).ftype}, not a file)
         | 
| 185 196 | 
             
                        else
         | 
| @@ -184,7 +184,7 @@ module Asciidoctor | |
| 184 184 | 
             
                end
         | 
| 185 185 |  | 
| 186 186 | 
             
                # Alias for backward compatibility.
         | 
| 187 | 
            -
                alias  | 
| 187 | 
            +
                alias convert_with_options convert
         | 
| 188 188 | 
             
              end
         | 
| 189 189 |  | 
| 190 190 | 
             
              # A module that can be used to mix the {#write} method into a {Converter}
         | 
| @@ -202,9 +202,9 @@ module Asciidoctor | |
| 202 202 | 
             
                  if target.respond_to? :write
         | 
| 203 203 | 
             
                    target.write output.chomp
         | 
| 204 204 | 
             
                    # ensure there's a trailing endline to be nice to terminals
         | 
| 205 | 
            -
                    target.write  | 
| 205 | 
            +
                    target.write LF
         | 
| 206 206 | 
             
                  else
         | 
| 207 | 
            -
                    :: | 
| 207 | 
            +
                    ::IO.write target, output
         | 
| 208 208 | 
             
                  end
         | 
| 209 209 | 
             
                  nil
         | 
| 210 210 | 
             
                end
         | 
| @@ -34,7 +34,7 @@ module Asciidoctor | |
| 34 34 | 
             
                  opts.empty? ? (send transform, node) : (send transform, node, opts)
         | 
| 35 35 | 
             
                end
         | 
| 36 36 |  | 
| 37 | 
            -
                alias  | 
| 37 | 
            +
                alias handles? respond_to?
         | 
| 38 38 |  | 
| 39 39 | 
             
                # Public: Returns the converted content of the {AbstractNode}.
         | 
| 40 40 | 
             
                #
         | 
| @@ -43,7 +43,7 @@ module Asciidoctor | |
| 43 43 | 
             
                  node.content
         | 
| 44 44 | 
             
                end
         | 
| 45 45 |  | 
| 46 | 
            -
                alias  | 
| 46 | 
            +
                alias pass content
         | 
| 47 47 |  | 
| 48 48 | 
             
                # Public: Skips conversion of the {AbstractNode}.
         | 
| 49 49 | 
             
                #
         | 
| @@ -29,7 +29,7 @@ module Asciidoctor | |
| 29 29 | 
             
                    result << '</listitem>'
         | 
| 30 30 | 
             
                  end
         | 
| 31 31 | 
             
                  result << %(</orderedlist>)
         | 
| 32 | 
            -
                  result *  | 
| 32 | 
            +
                  result * LF
         | 
| 33 33 | 
             
                end
         | 
| 34 34 |  | 
| 35 35 | 
             
                def inline_anchor node
         | 
| @@ -66,7 +66,7 @@ module Asciidoctor | |
| 66 66 | 
             
                  result << %(<email>#{doc.attr email_key}</email>) if doc.attr? email_key
         | 
| 67 67 | 
             
                  result << '</author>'
         | 
| 68 68 |  | 
| 69 | 
            -
                  result *  | 
| 69 | 
            +
                  result * LF
         | 
| 70 70 | 
             
                end
         | 
| 71 71 |  | 
| 72 72 | 
             
                def common_attributes id, role = nil, reftext = nil
         | 
| @@ -4,6 +4,8 @@ module Asciidoctor | |
| 4 4 | 
             
              # similar to the docbook45 backend from AsciiDoc Python, but migrated to the
         | 
| 5 5 | 
             
              # DocBook 5 specification.
         | 
| 6 6 | 
             
              class Converter::DocBook5Converter < Converter::BuiltIn
         | 
| 7 | 
            +
                ImageMacroRx = /^image::?(.+?)\[(.*?)\]$/
         | 
| 8 | 
            +
             | 
| 7 9 | 
             
                def document node
         | 
| 8 10 | 
             
                  result = []
         | 
| 9 11 | 
             
                  if (root_tag_name = node.doctype) == 'manpage'
         | 
| @@ -29,34 +31,25 @@ module Asciidoctor | |
| 29 31 | 
             
                  end
         | 
| 30 32 | 
             
                  lang_attribute = (node.attr? 'nolang') ? nil : %( #{lang_attribute_name}="#{node.attr 'lang', 'en'}")
         | 
| 31 33 | 
             
                  result << %(<#{root_tag_name}#{document_ns_attributes node}#{lang_attribute}>)
         | 
| 32 | 
            -
                  result << (document_info_element node, root_tag_name)
         | 
| 34 | 
            +
                  result << (document_info_element node, root_tag_name) unless node.noheader
         | 
| 33 35 | 
             
                  result << node.content if node.blocks?
         | 
| 34 36 | 
             
                  unless (footer_docinfo = node.docinfo :footer).empty?
         | 
| 35 37 | 
             
                    result << footer_docinfo
         | 
| 36 38 | 
             
                  end
         | 
| 37 39 | 
             
                  result << %(</#{root_tag_name}>)
         | 
| 38 40 |  | 
| 39 | 
            -
                  result *  | 
| 41 | 
            +
                  result * LF
         | 
| 40 42 | 
             
                end
         | 
| 41 43 |  | 
| 42 | 
            -
                alias  | 
| 44 | 
            +
                alias embedded content
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                MANPAGE_SECTION_TAGS = { 'section' => 'refsection', 'synopsis' => 'refsynopsisdiv' }
         | 
| 43 47 |  | 
| 44 48 | 
             
                def section node
         | 
| 45 | 
            -
                   | 
| 46 | 
            -
             | 
| 47 | 
            -
                    if (tag_name = node.sectname).start_with? 'sect'
         | 
| 48 | 
            -
                      # a normal child section of a special section
         | 
| 49 | 
            -
                      tag_name = 'section'
         | 
| 50 | 
            -
                    end
         | 
| 49 | 
            +
                  if node.document.doctype == 'manpage'
         | 
| 50 | 
            +
                    tag_name = MANPAGE_SECTION_TAGS[tag_name = node.sectname] || tag_name
         | 
| 51 51 | 
             
                  else
         | 
| 52 | 
            -
                    tag_name =  | 
| 53 | 
            -
                  end
         | 
| 54 | 
            -
                  if doctype == 'manpage'
         | 
| 55 | 
            -
                    if tag_name == 'section'
         | 
| 56 | 
            -
                      tag_name = 'refsection'
         | 
| 57 | 
            -
                    elsif tag_name == 'synopsis'
         | 
| 58 | 
            -
                      tag_name = 'refsynopsisdiv'
         | 
| 59 | 
            -
                    end
         | 
| 52 | 
            +
                    tag_name = node.sectname
         | 
| 60 53 | 
             
                  end
         | 
| 61 54 | 
             
                  %(<#{tag_name}#{common_attributes node.id, node.role, node.reftext}>
         | 
| 62 55 | 
             
            <title>#{node.title}</title>
         | 
| @@ -70,7 +63,7 @@ module Asciidoctor | |
| 70 63 | 
             
            </#{tag_name}>)
         | 
| 71 64 | 
             
                end
         | 
| 72 65 |  | 
| 73 | 
            -
                alias  | 
| 66 | 
            +
                alias audio skip
         | 
| 74 67 |  | 
| 75 68 | 
             
                def colist node
         | 
| 76 69 | 
             
                  result = []
         | 
| @@ -83,16 +76,10 @@ module Asciidoctor | |
| 83 76 | 
             
                    result << '</callout>'
         | 
| 84 77 | 
             
                  end
         | 
| 85 78 | 
             
                  result << %(</calloutlist>)
         | 
| 86 | 
            -
                  result *  | 
| 79 | 
            +
                  result * LF
         | 
| 87 80 | 
             
                end
         | 
| 88 81 |  | 
| 89 82 | 
             
                (DLIST_TAGS = {
         | 
| 90 | 
            -
                  'labeled' => {
         | 
| 91 | 
            -
                    :list  => 'variablelist',
         | 
| 92 | 
            -
                    :entry => 'varlistentry',
         | 
| 93 | 
            -
                    :term  => 'term',
         | 
| 94 | 
            -
                    :item  => 'listitem'
         | 
| 95 | 
            -
                  },
         | 
| 96 83 | 
             
                  'qanda' => {
         | 
| 97 84 | 
             
                    :list  => 'qandaset',
         | 
| 98 85 | 
             
                    :entry => 'qandaentry',
         | 
| @@ -106,7 +93,7 @@ module Asciidoctor | |
| 106 93 | 
             
                    :term  => 'glossterm',
         | 
| 107 94 | 
             
                    :item  => 'glossdef'
         | 
| 108 95 | 
             
                  }
         | 
| 109 | 
            -
                }).default = { # default  | 
| 96 | 
            +
                }).default = { # default is variable
         | 
| 110 97 | 
             
                  :list => 'variablelist',
         | 
| 111 98 | 
             
                  :entry => 'varlistentry',
         | 
| 112 99 | 
             
                  :term => 'term',
         | 
| @@ -172,7 +159,7 @@ module Asciidoctor | |
| 172 159 | 
             
                    result << %(</#{list_tag}>) if list_tag
         | 
| 173 160 | 
             
                  end
         | 
| 174 161 |  | 
| 175 | 
            -
                  result *  | 
| 162 | 
            +
                  result * LF
         | 
| 176 163 | 
             
                end
         | 
| 177 164 |  | 
| 178 165 | 
             
                def example node
         | 
| @@ -193,19 +180,29 @@ module Asciidoctor | |
| 193 180 | 
             
                end
         | 
| 194 181 |  | 
| 195 182 | 
             
                def image node
         | 
| 196 | 
            -
                   | 
| 197 | 
            -
                   | 
| 198 | 
            -
                   | 
| 199 | 
            -
             | 
| 200 | 
            -
             | 
| 201 | 
            -
             | 
| 183 | 
            +
                  # NOTE according to the DocBook spec, content area, scaling, and scaling to fit are mutually exclusive
         | 
| 184 | 
            +
                  # See http://tdg.docbook.org/tdg/4.5/imagedata-x.html#d0e79635
         | 
| 185 | 
            +
                  if node.attr? 'scaledwidth'
         | 
| 186 | 
            +
                    width_attribute = %( width="#{node.attr 'scaledwidth'}")
         | 
| 187 | 
            +
                    depth_attribute = nil
         | 
| 188 | 
            +
                    scale_attribute = nil
         | 
| 189 | 
            +
                  elsif node.attr? 'scale'
         | 
| 190 | 
            +
                    # QUESTION should we set the viewport using width and depth? (the scaled image would be contained within this box)
         | 
| 191 | 
            +
                    #width_attribute = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : nil
         | 
| 192 | 
            +
                    #depth_attribute = (node.attr? 'height') ? %( depth="#{node.attr 'height'}") : nil
         | 
| 193 | 
            +
                    scale_attribute = %( scale="#{node.attr 'scale'}")
         | 
| 194 | 
            +
                  else
         | 
| 195 | 
            +
                    width_attribute = (node.attr? 'width') ? %( contentwidth="#{node.attr 'width'}") : nil
         | 
| 196 | 
            +
                    depth_attribute = (node.attr? 'height') ? %( contentdepth="#{node.attr 'height'}") : nil
         | 
| 197 | 
            +
                    scale_attribute = nil
         | 
| 198 | 
            +
                  end
         | 
| 202 199 | 
             
                  align_attribute = (node.attr? 'align') ? %( align="#{node.attr 'align'}") : nil
         | 
| 203 200 |  | 
| 204 201 | 
             
                  mediaobject = %(<mediaobject>
         | 
| 205 202 | 
             
            <imageobject>
         | 
| 206 | 
            -
            <imagedata fileref="#{node.image_uri(node.attr 'target')}"#{width_attribute}#{depth_attribute}#{ | 
| 203 | 
            +
            <imagedata fileref="#{node.image_uri(node.attr 'target')}"#{width_attribute}#{depth_attribute}#{scale_attribute}#{align_attribute}/>
         | 
| 207 204 | 
             
            </imageobject>
         | 
| 208 | 
            -
            <textobject><phrase>#{node. | 
| 205 | 
            +
            <textobject><phrase>#{node.alt}</phrase></textobject>
         | 
| 209 206 | 
             
            </mediaobject>)
         | 
| 210 207 |  | 
| 211 208 | 
             
                  if node.title?
         | 
| @@ -224,7 +221,7 @@ module Asciidoctor | |
| 224 221 | 
             
                  informal = !node.title?
         | 
| 225 222 | 
             
                  listing_attributes = (common_attributes node.id, node.role, node.reftext)
         | 
| 226 223 | 
             
                  if node.style == 'source' && (node.attr? 'language')
         | 
| 227 | 
            -
                    numbering = (node.attr? 'linenums') ? 'numbered' : 'unnumbered'
         | 
| 224 | 
            +
                    numbering = (node.attr? 'linenums', nil, false) ? 'numbered' : 'unnumbered'
         | 
| 228 225 | 
             
                    listing_content = %(<programlisting#{informal ? listing_attributes : nil} language="#{node.attr 'language', nil, false}" linenumbering="#{numbering}">#{node.content}</programlisting>)
         | 
| 229 226 | 
             
                  else
         | 
| 230 227 | 
             
                    listing_content = %(<screen#{informal ? listing_attributes : nil}>#{node.content}</screen>)
         | 
| @@ -256,10 +253,12 @@ module Asciidoctor | |
| 256 253 |  | 
| 257 254 | 
             
                def stem node
         | 
| 258 255 | 
             
                  if (idx = node.subs.index :specialcharacters)
         | 
| 259 | 
            -
                    node.subs. | 
| 256 | 
            +
                    node.subs.delete_at idx
         | 
| 257 | 
            +
                    equation = node.content
         | 
| 258 | 
            +
                    idx > 0 ? (node.subs.insert idx, :specialcharacters) : (node.subs.unshift :specialcharacters)
         | 
| 259 | 
            +
                  else
         | 
| 260 | 
            +
                    equation = node.content
         | 
| 260 261 | 
             
                  end
         | 
| 261 | 
            -
                  equation = node.content
         | 
| 262 | 
            -
                  node.subs.insert idx, :specialcharacters if idx
         | 
| 263 262 | 
             
                  if node.style == 'asciimath'
         | 
| 264 263 | 
             
                    if ((defined? ::AsciiMath) || ((defined? @asciimath_available) ? @asciimath_available :
         | 
| 265 264 | 
             
                        (@asciimath_available = Helpers.require_library 'asciimath', true, :warn)))
         | 
| @@ -299,13 +298,13 @@ module Asciidoctor | |
| 299 298 | 
             
                    result << '</listitem>'
         | 
| 300 299 | 
             
                  end
         | 
| 301 300 | 
             
                  result << %(</orderedlist>)
         | 
| 302 | 
            -
                  result *  | 
| 301 | 
            +
                  result * LF
         | 
| 303 302 | 
             
                end
         | 
| 304 303 |  | 
| 305 304 | 
             
                def open node
         | 
| 306 305 | 
             
                  case node.style
         | 
| 307 306 | 
             
                  when 'abstract'
         | 
| 308 | 
            -
                    if node.parent == node.document && node.document. | 
| 307 | 
            +
                    if node.parent == node.document && node.document.doctype == 'book'
         | 
| 309 308 | 
             
                      warn 'asciidoctor: WARNING: abstract block cannot be used in a document without a title when doctype is book. Excluding block content.'
         | 
| 310 309 | 
             
                      ''
         | 
| 311 310 | 
             
                    else
         | 
| @@ -368,7 +367,7 @@ module Asciidoctor | |
| 368 367 | 
             
                  end
         | 
| 369 368 | 
             
                  result << (resolve_content node)
         | 
| 370 369 | 
             
                  result << '</blockquote>'
         | 
| 371 | 
            -
                  result *  | 
| 370 | 
            +
                  result * LF
         | 
| 372 371 | 
             
                end
         | 
| 373 372 |  | 
| 374 373 | 
             
                def thematic_break node
         | 
| @@ -382,7 +381,6 @@ module Asciidoctor | |
| 382 381 | 
             
                end
         | 
| 383 382 |  | 
| 384 383 | 
             
                TABLE_PI_NAMES = ['dbhtml', 'dbfo', 'dblatex']
         | 
| 385 | 
            -
                TABLE_SECTIONS = [:head, :foot, :body]
         | 
| 386 384 |  | 
| 387 385 | 
             
                def table node
         | 
| 388 386 | 
             
                  has_body = false
         | 
| @@ -407,10 +405,11 @@ module Asciidoctor | |
| 407 405 | 
             
                  node.columns.each do |col|
         | 
| 408 406 | 
             
                    result << %(<colspec colname="col_#{col.attr 'colnumber'}" colwidth="#{col.attr col_width_key}*"/>)
         | 
| 409 407 | 
             
                  end
         | 
| 410 | 
            -
                   | 
| 411 | 
            -
                     | 
| 412 | 
            -
                     | 
| 413 | 
            -
                     | 
| 408 | 
            +
                  node.rows.by_section.each do |tsec, rows|
         | 
| 409 | 
            +
                    next if rows.empty?
         | 
| 410 | 
            +
                    has_body = true if tsec == :body
         | 
| 411 | 
            +
                    result << %(<t#{tsec}>)
         | 
| 412 | 
            +
                    rows.each do |row|
         | 
| 414 413 | 
             
                      result << '<row>'
         | 
| 415 414 | 
             
                      row.each do |cell|
         | 
| 416 415 | 
             
                        halign_attribute = (cell.attr? 'halign') ? %( align="#{cell.attr 'halign'}") : nil
         | 
| @@ -419,20 +418,20 @@ module Asciidoctor | |
| 419 418 | 
             
                        rowspan_attribute = cell.rowspan ? %( morerows="#{cell.rowspan - 1}") : nil
         | 
| 420 419 | 
             
                        # NOTE <entry> may not have whitespace (e.g., line breaks) as a direct descendant according to DocBook rules
         | 
| 421 420 | 
             
                        entry_start = %(<entry#{halign_attribute}#{valign_attribute}#{colspan_attribute}#{rowspan_attribute}>)
         | 
| 422 | 
            -
                         | 
| 423 | 
            -
                          cell.text
         | 
| 421 | 
            +
                        if tsec == :head
         | 
| 422 | 
            +
                          cell_content = cell.text
         | 
| 424 423 | 
             
                        else
         | 
| 425 424 | 
             
                          case cell.style
         | 
| 426 425 | 
             
                          when :asciidoc
         | 
| 427 | 
            -
                            cell.content
         | 
| 426 | 
            +
                            cell_content = cell.content
         | 
| 428 427 | 
             
                          when :verse
         | 
| 429 | 
            -
                            %(<literallayout>#{cell.text}</literallayout>)
         | 
| 428 | 
            +
                            cell_content = %(<literallayout>#{cell.text}</literallayout>)
         | 
| 430 429 | 
             
                          when :literal
         | 
| 431 | 
            -
                            %(<literallayout class="monospaced">#{cell.text}</literallayout>)
         | 
| 430 | 
            +
                            cell_content = %(<literallayout class="monospaced">#{cell.text}</literallayout>)
         | 
| 432 431 | 
             
                          when :header
         | 
| 433 | 
            -
                            cell.content. | 
| 432 | 
            +
                            cell_content = (cell_content = cell.content).empty? ? '' : %(<simpara><emphasis role="strong">#{cell_content * '</emphasis></simpara><simpara><emphasis role="strong">'}</emphasis></simpara>)
         | 
| 434 433 | 
             
                          else
         | 
| 435 | 
            -
                            cell.content. | 
| 434 | 
            +
                            cell_content = (cell_content = cell.content).empty? ? '' : %(<simpara>#{cell_content * '</simpara><simpara>'}</simpara>)
         | 
| 436 435 | 
             
                          end
         | 
| 437 436 | 
             
                        end
         | 
| 438 437 | 
             
                        entry_end = (node.document.attr? 'cellbgcolor') ? %(<?dbfo bgcolor="#{node.document.attr 'cellbgcolor'}"?></entry>) : '</entry>'
         | 
| @@ -440,16 +439,16 @@ module Asciidoctor | |
| 440 439 | 
             
                      end
         | 
| 441 440 | 
             
                      result << '</row>'
         | 
| 442 441 | 
             
                    end
         | 
| 443 | 
            -
                    result << %(</t#{ | 
| 442 | 
            +
                    result << %(</t#{tsec}>)
         | 
| 444 443 | 
             
                  end
         | 
| 445 444 | 
             
                  result << '</tgroup>'
         | 
| 446 445 | 
             
                  result << %(</#{tag_name}>)
         | 
| 447 446 |  | 
| 448 447 | 
             
                  warn 'asciidoctor: WARNING: tables must have at least one body row' unless has_body
         | 
| 449 | 
            -
                  result *  | 
| 448 | 
            +
                  result * LF
         | 
| 450 449 | 
             
                end
         | 
| 451 450 |  | 
| 452 | 
            -
                alias  | 
| 451 | 
            +
                alias toc skip
         | 
| 453 452 |  | 
| 454 453 | 
             
                def ulist node
         | 
| 455 454 | 
             
                  result = []
         | 
| @@ -482,7 +481,7 @@ module Asciidoctor | |
| 482 481 | 
             
                    result << '</itemizedlist>'
         | 
| 483 482 | 
             
                  end
         | 
| 484 483 |  | 
| 485 | 
            -
                  result *  | 
| 484 | 
            +
                  result * LF
         | 
| 486 485 | 
             
                end
         | 
| 487 486 |  | 
| 488 487 | 
             
                def verse node
         | 
| @@ -501,15 +500,15 @@ module Asciidoctor | |
| 501 500 | 
             
                  end
         | 
| 502 501 | 
             
                  result << %(<literallayout>#{node.content}</literallayout>)
         | 
| 503 502 | 
             
                  result << '</blockquote>'
         | 
| 504 | 
            -
                  result *  | 
| 503 | 
            +
                  result * LF
         | 
| 505 504 | 
             
                end
         | 
| 506 505 |  | 
| 507 | 
            -
                alias  | 
| 506 | 
            +
                alias video skip
         | 
| 508 507 |  | 
| 509 508 | 
             
                def inline_anchor node
         | 
| 510 509 | 
             
                  case node.type
         | 
| 511 510 | 
             
                  when :ref
         | 
| 512 | 
            -
                    %(<anchor#{common_attributes node. | 
| 511 | 
            +
                    %(<anchor#{common_attributes((id = node.id), nil, node.reftext || %([#{id}]))}/>)
         | 
| 513 512 | 
             
                  when :xref
         | 
| 514 513 | 
             
                    if (path = node.attributes['path'])
         | 
| 515 514 | 
             
                      # QUESTION should we use refid as fallback text instead? (like the html5 backend?)
         | 
| @@ -521,8 +520,8 @@ module Asciidoctor | |
| 521 520 | 
             
                  when :link
         | 
| 522 521 | 
             
                    %(<link xl:href="#{node.target}">#{node.text}</link>)
         | 
| 523 522 | 
             
                  when :bibref
         | 
| 524 | 
            -
                     | 
| 525 | 
            -
                    %(<anchor#{common_attributes  | 
| 523 | 
            +
                    # NOTE technically node.text should be node.reftext, but subs have already been applied to text
         | 
| 524 | 
            +
                    %(<anchor#{common_attributes node.id, nil, (text = node.text)}/>#{text})
         | 
| 526 525 | 
             
                  else
         | 
| 527 526 | 
             
                    warn %(asciidoctor: WARNING: unknown anchor type: #{node.type.inspect})
         | 
| 528 527 | 
             
                  end
         | 
| @@ -555,7 +554,7 @@ module Asciidoctor | |
| 555 554 | 
             
            <imageobject>
         | 
| 556 555 | 
             
            <imagedata fileref="#{node.type == 'icon' ? (node.icon_uri node.target) : (node.image_uri node.target)}"#{width_attribute}#{depth_attribute}/>
         | 
| 557 556 | 
             
            </imageobject>
         | 
| 558 | 
            -
            <textobject><phrase>#{node. | 
| 557 | 
            +
            <textobject><phrase>#{node.alt}</phrase></textobject>
         | 
| 559 558 | 
             
            </inlinemediaobject>)
         | 
| 560 559 | 
             
                end
         | 
| 561 560 |  | 
| @@ -578,7 +577,7 @@ module Asciidoctor | |
| 578 577 | 
             
                    result << %(<indexterm>
         | 
| 579 578 | 
             
            <primary>#{terms[-1]}</primary>
         | 
| 580 579 | 
             
            </indexterm>)
         | 
| 581 | 
            -
                    result *  | 
| 580 | 
            +
                    result * LF
         | 
| 582 581 | 
             
                  end
         | 
| 583 582 | 
             
                end
         | 
| 584 583 |  | 
| @@ -586,32 +585,33 @@ module Asciidoctor | |
| 586 585 | 
             
                  if (keys = node.attr 'keys').size == 1
         | 
| 587 586 | 
             
                    %(<keycap>#{keys[0]}</keycap>)
         | 
| 588 587 | 
             
                  else
         | 
| 589 | 
            -
                    %(<keycombo>#{keys | 
| 588 | 
            +
                    %(<keycombo><keycap>#{keys * '</keycap><keycap>'}</keycap></keycombo>)
         | 
| 590 589 | 
             
                  end
         | 
| 591 590 | 
             
                end
         | 
| 592 591 |  | 
| 593 592 | 
             
                def inline_menu node
         | 
| 594 593 | 
             
                  menu = node.attr 'menu'
         | 
| 595 | 
            -
                  if  | 
| 596 | 
            -
                     | 
| 597 | 
            -
             | 
| 598 | 
            -
             | 
| 599 | 
            -
             | 
| 594 | 
            +
                  if (submenus = node.attr 'submenus').empty?
         | 
| 595 | 
            +
                    if (menuitem = node.attr 'menuitem', nil, false)
         | 
| 596 | 
            +
                      %(<menuchoice><guimenu>#{menu}</guimenu> <guimenuitem>#{menuitem}</guimenuitem></menuchoice>)
         | 
| 597 | 
            +
                    else
         | 
| 598 | 
            +
                      %(<guimenu>#{menu}</guimenu>)
         | 
| 599 | 
            +
                    end
         | 
| 600 600 | 
             
                  else
         | 
| 601 | 
            -
                    %(<guimenu>#{menu}</guimenu>)
         | 
| 601 | 
            +
                    %(<menuchoice><guimenu>#{menu}</guimenu> <guisubmenu>#{submenus * '</guisubmenu> <guisubmenu>'}</guisubmenu> <guimenuitem>#{node.attr 'menuitem'}</guimenuitem></menuchoice>)
         | 
| 602 602 | 
             
                  end
         | 
| 603 603 | 
             
                end
         | 
| 604 604 |  | 
| 605 605 | 
             
                (QUOTE_TAGS = {
         | 
| 606 | 
            +
                  :monospaced  => ['<literal>',                '</literal>',     false],
         | 
| 606 607 | 
             
                  :emphasis    => ['<emphasis>',               '</emphasis>',    true],
         | 
| 607 608 | 
             
                  :strong      => ['<emphasis role="strong">', '</emphasis>',    true],
         | 
| 608 | 
            -
                  :monospaced  => ['<literal>',                '</literal>',     false],
         | 
| 609 | 
            -
                  :superscript => ['<superscript>',            '</superscript>', false],
         | 
| 610 | 
            -
                  :subscript   => ['<subscript>',              '</subscript>',   false],
         | 
| 611 609 | 
             
                  :double      => ['“',                  '”',        true],
         | 
| 612 610 | 
             
                  :single      => ['‘',                  '’',        true],
         | 
| 613 | 
            -
                  :mark        => ['<emphasis role="marked">', '</emphasis>',    false]
         | 
| 614 | 
            -
             | 
| 611 | 
            +
                  :mark        => ['<emphasis role="marked">', '</emphasis>',    false],
         | 
| 612 | 
            +
                  :superscript => ['<superscript>',            '</superscript>', false],
         | 
| 613 | 
            +
                  :subscript   => ['<subscript>',              '</subscript>',   false]
         | 
| 614 | 
            +
                }).default = ['', '', true]
         | 
| 615 615 |  | 
| 616 616 | 
             
                def inline_quoted node
         | 
| 617 617 | 
             
                  if (type = node.type) == :asciimath
         | 
| @@ -628,11 +628,11 @@ module Asciidoctor | |
| 628 628 | 
             
                  else
         | 
| 629 629 | 
             
                    open, close, supports_phrase = QUOTE_TAGS[type]
         | 
| 630 630 | 
             
                    text = node.text
         | 
| 631 | 
            -
                    if  | 
| 631 | 
            +
                    if node.role
         | 
| 632 632 | 
             
                      if supports_phrase
         | 
| 633 | 
            -
                        quoted_text = %(#{open}<phrase role="#{role}">#{text}</phrase>#{close})
         | 
| 633 | 
            +
                        quoted_text = %(#{open}<phrase role="#{node.role}">#{text}</phrase>#{close})
         | 
| 634 634 | 
             
                      else
         | 
| 635 | 
            -
                        quoted_text = %(#{open.chop} role="#{role}">#{text}#{close})
         | 
| 635 | 
            +
                        quoted_text = %(#{open.chop} role="#{node.role}">#{text}#{close})
         | 
| 636 636 | 
             
                      end
         | 
| 637 637 | 
             
                    else
         | 
| 638 638 | 
             
                      quoted_text = %(#{open}#{text}#{close})
         | 
| @@ -658,14 +658,20 @@ module Asciidoctor | |
| 658 658 | 
             
                  result << %(<email>#{doc.attr email_key}</email>) if doc.attr? email_key
         | 
| 659 659 | 
             
                  result << '</author>'
         | 
| 660 660 |  | 
| 661 | 
            -
                  result *  | 
| 661 | 
            +
                  result * LF
         | 
| 662 662 | 
             
                end
         | 
| 663 663 |  | 
| 664 664 | 
             
                def common_attributes id, role = nil, reftext = nil
         | 
| 665 | 
            -
                   | 
| 666 | 
            -
                   | 
| 667 | 
            -
                   | 
| 668 | 
            -
             | 
| 665 | 
            +
                  attrs = id ? %( xml:id="#{id}") : ''
         | 
| 666 | 
            +
                  attrs = %(#{attrs} role="#{role}") if role
         | 
| 667 | 
            +
                  if reftext
         | 
| 668 | 
            +
                    if (reftext.include? '<') && ((reftext = reftext.gsub XmlSanitizeRx, '').include? ' ')
         | 
| 669 | 
            +
                      reftext = (reftext.squeeze ' ').strip
         | 
| 670 | 
            +
                    end
         | 
| 671 | 
            +
                    reftext = (reftext.gsub '"', '"') if reftext.include? '"'
         | 
| 672 | 
            +
                    attrs = %(#{attrs} xreflabel="#{reftext}")
         | 
| 673 | 
            +
                  end
         | 
| 674 | 
            +
                  attrs
         | 
| 669 675 | 
             
                end
         | 
| 670 676 |  | 
| 671 677 | 
             
                def doctype_declaration root_tag_name
         | 
| @@ -673,7 +679,7 @@ module Asciidoctor | |
| 673 679 | 
             
                end
         | 
| 674 680 |  | 
| 675 681 | 
             
                def document_info_element doc, info_tag_prefix, use_info_tag_prefix = false
         | 
| 676 | 
            -
                  info_tag_prefix =  | 
| 682 | 
            +
                  info_tag_prefix = nil unless use_info_tag_prefix
         | 
| 677 683 | 
             
                  result = []
         | 
| 678 684 | 
             
                  result << %(<#{info_tag_prefix}info>)
         | 
| 679 685 | 
             
                  result << document_title_tags(doc.doctitle :partition => true, :use_fallback => true) unless doc.notitle
         | 
| @@ -703,6 +709,16 @@ module Asciidoctor | |
| 703 709 | 
             
                      result << %(</revision>
         | 
| 704 710 | 
             
            </revhistory>)
         | 
| 705 711 | 
             
                    end
         | 
| 712 | 
            +
                    unless use_info_tag_prefix
         | 
| 713 | 
            +
                      if (doc.attr? 'front-cover-image') || (doc.attr? 'back-cover-image')
         | 
| 714 | 
            +
                        if (back_cover_tag = cover_tag doc, 'back')
         | 
| 715 | 
            +
                          result << (cover_tag doc, 'front', true)
         | 
| 716 | 
            +
                          result << back_cover_tag
         | 
| 717 | 
            +
                        elsif (front_cover_tag = cover_tag doc, 'front')
         | 
| 718 | 
            +
                          result << front_cover_tag
         | 
| 719 | 
            +
                        end
         | 
| 720 | 
            +
                      end
         | 
| 721 | 
            +
                    end
         | 
| 706 722 | 
             
                    unless (head_docinfo = doc.docinfo).empty?
         | 
| 707 723 | 
             
                      result << head_docinfo
         | 
| 708 724 | 
             
                    end
         | 
| @@ -721,7 +737,7 @@ module Asciidoctor | |
| 721 737 | 
             
                    result << '</refnamediv>'
         | 
| 722 738 | 
             
                  end
         | 
| 723 739 |  | 
| 724 | 
            -
                  result *  | 
| 740 | 
            +
                  result * LF
         | 
| 725 741 | 
             
                end
         | 
| 726 742 |  | 
| 727 743 | 
             
                def document_ns_attributes doc
         | 
| @@ -749,5 +765,34 @@ module Asciidoctor | |
| 749 765 | 
             
                def title_tag node, optional = true
         | 
| 750 766 | 
             
                  !optional || node.title? ? %(<title>#{node.title}</title>\n) : nil
         | 
| 751 767 | 
             
                end
         | 
| 768 | 
            +
             | 
| 769 | 
            +
                def cover_tag doc, face, use_placeholder = false
         | 
| 770 | 
            +
                  if (cover_image = doc.attr %(#{face}-cover-image))
         | 
| 771 | 
            +
                    width_attr = nil
         | 
| 772 | 
            +
                    depth_attr = nil
         | 
| 773 | 
            +
                    if (cover_image.include? ':') && ImageMacroRx =~ cover_image
         | 
| 774 | 
            +
                      cover_image = doc.image_uri $1
         | 
| 775 | 
            +
                      unless $2.empty?
         | 
| 776 | 
            +
                        attrs = (AttributeList.new $2).parse ['alt', 'width', 'height']
         | 
| 777 | 
            +
                        if attrs.key? 'scaledwidth'
         | 
| 778 | 
            +
                          # NOTE scalefit="1" is the default in this case
         | 
| 779 | 
            +
                          width_attr = %( width="#{attrs['scaledwidth']}")
         | 
| 780 | 
            +
                        else
         | 
| 781 | 
            +
                          width_attr = %( contentwidth="#{attrs['width']}") if attrs.key? 'width'
         | 
| 782 | 
            +
                          depth_attr = %( contentdepth="#{attrs['height']}") if attrs.key? 'height'
         | 
| 783 | 
            +
                        end
         | 
| 784 | 
            +
                      end
         | 
| 785 | 
            +
                    end
         | 
| 786 | 
            +
                    %(<cover role="#{face}">
         | 
| 787 | 
            +
            <mediaobject>
         | 
| 788 | 
            +
            <imageobject>
         | 
| 789 | 
            +
            <imagedata fileref="#{cover_image}"#{width_attr}#{depth_attr}/>
         | 
| 790 | 
            +
            </imageobject>
         | 
| 791 | 
            +
            </mediaobject>
         | 
| 792 | 
            +
            </cover>)
         | 
| 793 | 
            +
                  elsif use_placeholder
         | 
| 794 | 
            +
                    %(<cover role="#{face}"/>)
         | 
| 795 | 
            +
                  end
         | 
| 796 | 
            +
                end
         | 
| 752 797 | 
             
              end
         | 
| 753 798 | 
             
            end
         |