# class Kramdown::Converter::Latex

Converts an element tree to LaTeX.

This converter uses ideas from other Markdown-to-LaTeX converters like Pandoc and Maruku.

You can customize this converter by sub-classing it and overriding the `convert_NAME` methods. Each such method takes the following parameters:

`el`

  The element of type `NAME` to be converted.

`opts`

  A hash containing processing options that are passed down from parent elements. The key :parent is always set and contains the parent element as value.

The return value of such a method has to be a string containing the element `el` formatted correctly as LaTeX markup.

### Public Class Methods

new(root, options) click to toggle source

Initialize the LaTeX converter with the `root` element and the conversion `options`.

Calls superclass method Kramdown::Converter::Base.new

    # File lib/kramdown/converter/latex.rb, line 33
    def initialize(root, options)
      super
      @data[:packages] = Set.new
    end

### Public Instance Methods

attribute_list(el) click to toggle source

Return a LaTeX comment containing all attributes as 'key=“value”' pairs.

    # File lib/kramdown/converter/latex.rb, line 588
    def attribute_list(el)
      attrs = el.attr.map {|k,v| v.nil? ? '' : " #{k}=\"#{v.to_s}\""}.compact.sort.join('')
      attrs = "   % #{attrs}" if !attrs.empty?
      attrs
    end

convert(el, opts = {}) click to toggle source

Dispatch the conversion of the element `el` to a `convert_TYPE` method using the `type` of the element.

    # File lib/kramdown/converter/latex.rb, line 40
    def convert(el, opts = {})
      send("convert_#{el.type}", el, opts)
    end

convert_a(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 209
    def convert_a(el, opts)
      url = el.attr['href']
      if url.start_with?('#')
        "\\hyperlink{#{url[1..-1].gsub('%', "\\%")}}{#{inner(el, opts)}}"
      else
        "\\href{#{url.gsub('%', "\\%")}}{#{inner(el, opts)}}"
      end
    end

convert_abbreviation(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 558
    def convert_abbreviation(el, opts)
      @data[:packages] += %w[acronym]
      "\\ac{#{normalize_abbreviation_key(el.value)}}"
    end

convert_blank(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 60
    def convert_blank(el, opts)
      opts[:result] =~ /\n\n\Z|\A\Z/ ? "" : "\n"
    end

convert_blockquote(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 105
    def convert_blockquote(el, opts)
      latex_environment(el.children.size > 1 ? 'quotation' : 'quote', el, inner(el, opts))
    end

convert_br(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 203
    def convert_br(el, opts)
      res = "\\newline"
      res << "\n" if (c = opts[:parent].children[opts[:index]+1]) && (c.type != :text || c.value !~ /^\s*\n/)
      res
    end

convert_codeblock(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 83
    def convert_codeblock(el, opts)
      show_whitespace = el.attr['class'].to_s =~ /\bshow-whitespaces\b/
      lang = extract_code_language(el.attr)

      if @options[:syntax_highlighter] == :minted &&
          (highlighted_code = highlight_code(el.value, lang, :block))
        @data[:packages] << 'minted'
        "#{latex_link_target(el)}#{highlighted_code}\n"
      elsif show_whitespace || lang
        options = []
        options << "showspaces=%s,showtabs=%s" % (show_whitespace ? ['true', 'true'] : ['false', 'false'])
        options << "language=#{lang}" if lang
        options << "basicstyle=\\ttfamily\\footnotesize,columns=fixed,frame=tlbr"
        id = el.attr['id']
        options << "label=#{id}" if id
        attrs = attribute_list(el)
        "#{latex_link_target(el)}\\begin{lstlisting}[#{options.join(',')}]\n#{el.value}\n\\end{lstlisting}#{attrs}\n"
      else
        "#{latex_link_target(el)}\\begin{verbatim}#{el.value}\\end{verbatim}\n"
      end
    end

convert_codespan(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 232
    def convert_codespan(el, opts)
      lang = extract_code_language(el.attr)
      if @options[:syntax_highlighter] == :minted &&
          (highlighted_code = highlight_code(el.value, lang, :span))
        @data[:packages] << 'minted'
        "#{latex_link_target(el)}#{highlighted_code}"
      else
        "\\texttt{#{latex_link_target(el)}#{escape(el.value)}}"
      end
    end

convert_comment(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 199
    def convert_comment(el, opts)
      el.value.split(/\n/).map {|l| "% #{l}"}.join("\n") << "\n"
    end

convert_dd(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 146
    def convert_dd(el, opts)
      "#{latex_link_target(el)}#{inner(el, opts)}\n\n"
    end

convert_dl(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 134
    def convert_dl(el, opts)
      latex_environment('description', el, inner(el, opts))
    end

convert_dt(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 142
    def convert_dt(el, opts)
      "\\item[#{inner(el, opts)}] "
    end

convert_em(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 256
    def convert_em(el, opts)
      "\\emph{#{latex_link_target(el)}#{inner(el, opts)}}"
    end

convert_entity(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 526
    def convert_entity(el, opts)
      entity_to_latex(el.value)
    end

convert_footnote(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 243
    def convert_footnote(el, opts)
      @data[:packages] << 'fancyvrb'
      "\\footnote{#{inner(el.value, opts).rstrip}}"
    end

convert_header(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 109
    def convert_header(el, opts)
      type = @options[:latex_headers][output_header_level(el.options[:level]) - 1]
      if ((id = el.attr['id']) ||
          (@options[:auto_ids] && (id = generate_id(el.options[:raw_text])))) && in_toc?(el)
        "\\#{type}{#{inner(el, opts)}}\\hypertarget{#{id}}{}\\label{#{id}}\n\n"
      else
        "\\#{type}*{#{inner(el, opts)}}\n\n"
      end
    end

convert_hr(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 119
    def convert_hr(el, opts)
      attrs = attribute_list(el)
      "#{latex_link_target(el)}\\begin{center}#{attrs}\n\\rule{3in}{0.4pt}\n\\end{center}#{attrs}\n"
    end

convert_html_element(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 150
    def convert_html_element(el, opts)
      if el.value == 'i' || el.value == 'em'
        "\\emph{#{inner(el, opts)}}"
      elsif el.value == 'b' || el.value == 'strong'
        "\\textbf{#{inner(el, opts)}}"
      else
        warning("Can't convert HTML element")
        ''
      end
    end

convert_img(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 218
    def convert_img(el, opts)
      line = el.options[:location]
      if el.attr['src'] =~ /^(https?|ftps?):\/\//
        warning("Cannot include non-local image#{line ? " (line #{line})" : ''}")
        ''
      elsif !el.attr['src'].empty?
        @data[:packages] << 'graphicx'
        "#{latex_link_target(el)}\\includegraphics{#{el.attr['src']}}"
      else
        warning("Cannot include image with empty path#{line ? " (line #{line})" : ''}")
        ''
      end
    end

convert_li(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 138
    def convert_li(el, opts)
      "\\item{} #{latex_link_target(el, true)}#{inner(el, opts).sub(/\n+\Z/, '')}\n"
    end

convert_math(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 545
    def convert_math(el, opts)
      @data[:packages] += %w[amssymb amsmath amsthm amsfonts]
      if el.options[:category] == :block
        if el.value =~ /\A\s*\begin\{/
          el.value
        else
          latex_environment('displaymath', el, el.value)
        end
      else
        "$#{el.value}$"
      end
    end

convert_ol(el, opts)
Alias for: convert_ul
convert_p(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 68
    def convert_p(el, opts)
      if el.children.size == 1 && el.children.first.type == :img && !(img = convert_img(el.children.first, opts)).empty?
        convert_standalone_image(el, opts, img)
      else
        "#{latex_link_target(el)}#{inner(el, opts)}\n\n"
      end
    end

convert_raw(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 248
    def convert_raw(el, opts)
      if !el.options[:type] || el.options[:type].empty? || el.options[:type].include?('latex')
        el.value + (el.options[:category] == :block ? "\n" : '')
      else
        ''
      end
    end

convert_root(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 56
    def convert_root(el, opts)
      inner(el, opts)
    end

convert_smart_quote(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 539
    def convert_smart_quote(el, opts)
      res = entity_to_latex(smart_quote_entity(el)).chomp('{}')
      res << "{}" if ((nel = opts[:parent].children[opts[:index]+1]) && nel.type == :smart_quote) || res =~ /\w$/
      res
    end

convert_standalone_image(el, opts, img) click to toggle source

Helper method used by `convert_p` to convert a paragraph that only contains a single :img element.

    # File lib/kramdown/converter/latex.rb, line 78
    def convert_standalone_image(el, opts, img)
      attrs = attribute_list(el)
      "\\begin{figure}#{attrs}\n\\begin{center}\n#{img}\n\\end{center}\n\\caption{#{escape(el.children.first.attr['alt'])}}\n#{latex_link_target(el, true)}\n\\end{figure}#{attrs}\n"
    end

convert_strong(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 260
    def convert_strong(el, opts)
      "\\textbf{#{latex_link_target(el)}#{inner(el, opts)}}"
    end

convert_table(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 172
    def convert_table(el, opts)
      @data[:packages] << 'longtable'
      align = el.options[:alignment].map {|a| TABLE_ALIGNMENT_CHAR[a]}.join('|')
      attrs = attribute_list(el)
      "#{latex_link_target(el)}\\begin{longtable}{|#{align}|}#{attrs}\n\\hline\n#{inner(el, opts)}\\hline\n\\end{longtable}#{attrs}\n\n"
    end

convert_tbody(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 183
    def convert_tbody(el, opts)
      inner(el, opts)
    end

convert_td(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 195
    def convert_td(el, opts)
      inner(el, opts)
    end

convert_text(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 64
    def convert_text(el, opts)
      escape(el.value)
    end

convert_tfoot(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 187
    def convert_tfoot(el, opts)
      "\\hline \\hline \n#{inner(el, opts)}"
    end

convert_thead(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 179
    def convert_thead(el, opts)
      "#{inner(el, opts)}\\hline\n"
    end

convert_tr(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 191
    def convert_tr(el, opts)
      el.children.map {|c| send("convert_#{c.type}", c, opts)}.join(' & ') << "\\\\\n"
    end

convert_typographic_sym(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 535
    def convert_typographic_sym(el, opts)
      TYPOGRAPHIC_SYMS[el.value]
    end

convert_ul(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 124
    def convert_ul(el, opts)
      if !@data[:has_toc] && (el.options[:ial][:refs].include?('toc') rescue nil)
        @data[:has_toc] = true
        '\tableofcontents'
      else
        latex_environment(el.type == :ul ? 'itemize' : 'enumerate', el, inner(el, opts))
      end
    end

Also aliased as: convert_ol
convert_xml_comment(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 161
    def convert_xml_comment(el, opts)
      el.value.split(/\n/).map {|l| "% #{l}"}.join("\n") + "\n"
    end

convert_xml_pi(el, opts) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 165
    def convert_xml_pi(el, opts)
      warning("Can't convert XML PI")
      ''
    end

entity_to_latex(entity) click to toggle source

    # File lib/kramdown/converter/latex.rb, line 515
    def entity_to_latex(entity)
      text, package = ENTITY_CONV_TABLE[entity.code_point]
      if text
        @data[:packages] << package if package
        text
      else
        warning("Couldn't find entity with code #{entity.code_point} in substitution table!")
        ''
      end
    end

escape(str) click to toggle source

Escape the special LaTeX characters in the string `str`.

    # File lib/kramdown/converter/latex.rb, line 607
    def escape(str)
      str.gsub(ESCAPE_RE) {|m| ESCAPE_MAP[m]}
    end

inner(el, opts) click to toggle source

Return the converted content of the children of `el` as a string.

    # File lib/kramdown/converter/latex.rb, line 45
    def inner(el, opts)
      result = ''
      options = opts.dup.merge(:parent => el)
      el.children.each_with_index do |inner_el, index|
        options[:index] = index
        options[:result] = result
        result << send("convert_#{inner_el.type}", inner_el, options)
      end
      result
    end

latex_environment(type, el, text) click to toggle source

Wrap the `text` inside a LaTeX environment of type `type`. The element `el` is passed on to the method attribute_list – the resulting string is appended to both the \begin and the \end lines of the LaTeX environment for easier post-processing of LaTeX environments.

    # File lib/kramdown/converter/latex.rb, line 571
    def latex_environment(type, el, text)
      attrs = attribute_list(el)
      "\\begin{#{type}}#{latex_link_target(el)}#{attrs}\n#{text.rstrip}\n\\end{#{type}}#{attrs}\n"
    end

latex_link_target(el, add_label = false) click to toggle source

Return a string containing a valid hypertarget command if the element has an ID defined, or `nil` otherwise. If the parameter `add_label` is `true`, a label command will also be used additionally to the hypertarget command.

    # File lib/kramdown/converter/latex.rb, line 579
    def latex_link_target(el, add_label = false)
      if (id = el.attr['id'])
        "\\hypertarget{#{id}}{}" << (add_label ? "\\label{#{id}}" : '')
      else
        nil
      end
    end

normalize_abbreviation_key(key) click to toggle source

Normalize the abbreviation key so that it only contains allowed ASCII character

    # File lib/kramdown/converter/latex.rb, line 564
    def normalize_abbreviation_key(key)
      key.gsub(/\W/) {|m| m.unpack('H*').first}
    end