class Asciidoctor::PreprocessorReader

def preprocess_include raw_target, raw_attributes

returns a Boolean indicating whether the line under the cursor has changed.

target slot of the include::[] macro
target - The name of the source document to include as specified in the

If none of the above apply, emit the include directive line verbatim.

of the Array of source data.
stack size, normalize the target path and read the lines onto the beginning
Otherwise, if the max depth is greater than 0, and is not exceeded by the

attributes to that processor and expect an Array of String lines in return.
Otherwise, if an include processor is specified pass the target and

directive line is emitted verbatim.
If SafeMode is SECURE or greater, the directive is ignore and the include

are as follows:
Preprocess the directive to include the target document. The scenarios

Internal: Preprocess the directive (macro) to include the target document.
def preprocess_include raw_target, raw_attributes
  if (target = @document.sub_attributes raw_target, :attribute_missing => 'drop-line').empty?
    if @document.attributes.fetch('attribute-missing', Compliance.attribute_missing) == 'skip'
      replace_line %(Unresolved directive in #{@path} - include::#{raw_target}[#{raw_attributes}])
      true
    else
      advance
      true
    end
  # assume that if an include processor is given, the developer wants
  # to handle when and how to process the include
  elsif include_processors? &&
      (extension = @include_processor_extensions.find {|candidate| candidate.instance.handles? target })
    advance
    # FIXME parse attributes if requested by extension
    extension.process_method[@document, self, target, AttributeList.new(raw_attributes).parse]
    true
  # if running in SafeMode::SECURE or greater, don't process this directive
  # however, be friendly and at least make it a link to the source document
  elsif @document.safe >= SafeMode::SECURE
    # FIXME we don't want to use a link macro if we are in a verbatim context
    replace_line %(link:#{target}[])
    true
  elsif (abs_maxdepth = @maxdepth[:abs]) > 0 && @include_stack.size >= abs_maxdepth
    warn %(asciidoctor: ERROR: #{line_info}: maximum include depth of #{@maxdepth[:rel]} exceeded)
    false
  elsif abs_maxdepth > 0
    if ::RUBY_ENGINE_OPAL
      # NOTE resolves uri relative to currently loaded document
      # NOTE we defer checking if file exists and catch the 404 error if it does not
      # TODO only use this logic if env-browser is set
      target_type = :file
      include_file = path = if @include_stack.empty?
        ::Dir.pwd == @document.base_dir ? target : (::File.join @dir, target)
      else
        ::File.join @dir, target
      end
    elsif target.include?(':') && UriSniffRx =~ target
      unless @document.attributes.has_key? 'allow-uri-read'
        replace_line %(link:#{target}[])
        return true
      end
      target_type = :uri
      include_file = path = target
      if @document.attributes.has_key? 'cache-uri'
        # caching requires the open-uri-cached gem to be installed
        # processing will be automatically aborted if these libraries can't be opened
        Helpers.require_library 'open-uri/cached', 'open-uri-cached'
      elsif !::RUBY_ENGINE_OPAL
        # autoload open-uri
        ::OpenURI
      end
    else
      target_type = :file
      # include file is resolved relative to dir of current include, or base_dir if within original docfile
      include_file = @document.normalize_system_path(target, @dir, nil, :target_name => 'include file')
      unless ::File.file? include_file
        warn "asciidoctor: WARNING: #{line_info}: include file not found: #{include_file}"
        replace_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
        return true
      end
      #path = @document.relative_path include_file
      path = PathResolver.new.relative_path include_file, @document.base_dir
    end
    inc_lines = nil
    tags = nil
    attributes = {}
    if !raw_attributes.empty?
      # QUESTION should we use @document.parse_attribues?
      attributes = AttributeList.new(raw_attributes).parse
      if attributes.has_key? 'lines'
        inc_lines = []
        attributes['lines'].split(DataDelimiterRx).each do |linedef|
          if linedef.include?('..')
            from, to = linedef.split('..').map(&:to_i)
            if to == -1
              inc_lines << from
              inc_lines << 1.0/0.0
            else
              inc_lines.concat ::Range.new(from, to).to_a
            end
          else
            inc_lines << linedef.to_i
          end
        end
        inc_lines = inc_lines.sort.uniq
      elsif attributes.has_key? 'tag'
        tags = [attributes['tag']].to_set
      elsif attributes.has_key? 'tags'
        tags = attributes['tags'].split(DataDelimiterRx).uniq.to_set
      end
    end
    if !inc_lines.nil?
      if !inc_lines.empty?
        selected = []
        inc_line_offset = 0
        inc_lineno = 0
        begin
          open(include_file, 'r') do |f|
            f.each_line do |l|
              inc_lineno += 1
              take = inc_lines[0]
              if take.is_a?(::Float) && take.infinite?
                selected.push l
                inc_line_offset = inc_lineno if inc_line_offset == 0
              else
                if f.lineno == take
                  selected.push l
                  inc_line_offset = inc_lineno if inc_line_offset == 0
                  inc_lines.shift
                end
                break if inc_lines.empty?
              end
            end
          end
        rescue
          warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{include_file})
          replace_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
          return true
        end
        advance
        # FIXME not accounting for skipped lines in reader line numbering
        push_include selected, include_file, path, inc_line_offset, attributes
      end
    elsif !tags.nil?
      if !tags.empty?
        selected = []
        inc_line_offset = 0
        inc_lineno = 0
        active_tag = nil
        tags_found = ::Set.new
        begin
          open(include_file, 'r') do |f|
            f.each_line do |l|
              inc_lineno += 1
              # must force encoding here since we're performing String operations on line
              l.force_encoding(::Encoding::UTF_8) if FORCE_ENCODING
              l = l.rstrip
              if active_tag
                if l.end_with?(%(end::#{active_tag}[])) && TagDirectiveRx =~ l
                  active_tag = nil
                else
                  selected.push l unless l.end_with?('[]') && TagDirectiveRx =~ l
                  inc_line_offset = inc_lineno if inc_line_offset == 0
                end
              else
                tags.each do |tag|
                  if l.end_with?(%(tag::#{tag}[])) && TagDirectiveRx =~ l
                    active_tag = tag
                    tags_found << tag
                    break
                  end
                end
              end
            end
          end
        rescue
          warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{include_file})
          replace_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
          return true
        end
        unless (missing_tags = tags.to_a - tags_found.to_a).empty?
          warn "asciidoctor: WARNING: #{line_info}: tag#{missing_tags.size > 1 ? 's' : nil} '#{missing_tags * ','}' not found in include #{target_type}: #{include_file}"
        end
        advance
        # FIXME not accounting for skipped lines in reader line numbering
        push_include selected, include_file, path, inc_line_offset, attributes
      end
    else
      begin
        advance
        push_include open(include_file, 'r') {|f| f.read }, include_file, path, 1, attributes
      rescue
        warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{include_file})
        replace_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
        return true
      end
    end
    true
  else
    false
  end
end