class Kramdown::Converter::Latex

correctly as LaTeX markup.
The return value of such a method has to be a string containing the element el formatted
key :parent is always set and contains the parent element as value.
[opts] A hash containing processing options that are passed down from parent elements. The

[el] The element of type NAME to be converted.
Each such method takes the following parameters:
You can customize this converter by sub-classing it and overriding the convert_NAME methods.
This converter uses ideas from other Markdown-to-LaTeX converters like Pandoc and Maruku.
Converts an element tree to LaTeX.

def attribute_list(el)

Return a LaTeX comment containing all attributes as 'key="value"' pairs.
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

def convert(el, opts = {})

the element.
Dispatch the conversion of the element +el+ to a +convert_TYPE+ method using the +type+ of
def convert(el, opts = {})
  send("convert_#{el.type}", el, opts)
end

def convert_a(el, opts)

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

def convert_abbreviation(el, opts)

def convert_abbreviation(el, opts)
  @data[:packages] += %w[acronym]
  "\\ac{#{normalize_abbreviation_key(el.value)}}"
end

def convert_blank(el, opts)

def convert_blank(el, opts)
  opts[:result] =~ /\n\n\Z|\A\Z/ ? "" : "\n"
end

def convert_blockquote(el, opts)

def convert_blockquote(el, opts)
  latex_environment(el.children.size > 1 ? 'quotation' : 'quote', el, inner(el, opts))
end

def convert_br(el, opts)

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

def convert_codeblock(el, opts)

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

def convert_codespan(el, opts)

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

def convert_comment(el, opts)

def convert_comment(el, opts)
  el.value.split(/\n/).map {|l| "% #{l}"}.join("\n") << "\n"
end

def convert_dd(el, opts)

def convert_dd(el, opts)
  "#{latex_link_target(el)}#{inner(el, opts)}\n\n"
end

def convert_dl(el, opts)

def convert_dl(el, opts)
  latex_environment('description', el, inner(el, opts))
end

def convert_dt(el, opts)

def convert_dt(el, opts)
  "\\item[#{inner(el, opts)}] "
end

def convert_em(el, opts)

def convert_em(el, opts)
  "\\emph{#{latex_link_target(el)}#{inner(el, opts)}}"
end

def convert_entity(el, opts)

def convert_entity(el, opts)
  entity_to_latex(el.value)
end

def convert_footnote(el, opts)

def convert_footnote(el, opts)
  @data[:packages] << 'fancyvrb'
  "\\footnote{#{inner(el.value, opts).rstrip}}"
end

def convert_header(el, opts)

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

def convert_hr(el, opts)

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

def convert_html_element(el, opts)

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

def convert_img(el, opts)

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

def convert_li(el, opts)

def convert_li(el, opts)
  "\\item{} #{latex_link_target(el, true)}#{inner(el, opts).sub(/\n+\Z/, '')}\n"
end

def convert_math(el, opts)

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

def convert_p(el, opts)

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

def convert_raw(el, opts)

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

def convert_root(el, opts)

def convert_root(el, opts)
  inner(el, opts)
end

def convert_smart_quote(el, opts)

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

def convert_standalone_image(el, opts, img)

element.
Helper method used by +convert_p+ to convert a paragraph that only contains a single :img
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

def convert_strong(el, opts)

def convert_strong(el, opts)
  "\\textbf{#{latex_link_target(el)}#{inner(el, opts)}}"
end

def convert_table(el, opts)

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

def convert_tbody(el, opts)

def convert_tbody(el, opts)
  inner(el, opts)
end

def convert_td(el, opts)

def convert_td(el, opts)
  inner(el, opts)
end

def convert_text(el, opts)

def convert_text(el, opts)
  escape(el.value)
end

def convert_tfoot(el, opts)

def convert_tfoot(el, opts)
  "\\hline \\hline \n#{inner(el, opts)}"
end

def convert_thead(el, opts)

def convert_thead(el, opts)
  "#{inner(el, opts)}\\hline\n"
end

def convert_tr(el, opts)

def convert_tr(el, opts)
  el.children.map {|c| send("convert_#{c.type}", c, opts)}.join(' & ') << "\\\\\n"
end

def convert_typographic_sym(el, opts)

:nodoc:
def convert_typographic_sym(el, opts)
  if (result = @options[:typographic_symbols][el.value])
    escape(result)
  else
    TYPOGRAPHIC_SYMS[el.value]
  end
end

def convert_ul(el, opts)

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

def convert_xml_comment(el, opts)

def convert_xml_comment(el, opts)
  el.value.split(/\n/).map {|l| "% #{l}"}.join("\n") + "\n"
end

def convert_xml_pi(el, opts)

def convert_xml_pi(el, opts)
  warning("Can't convert XML PI")
  ''
end

def entity_to_latex(entity)

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

def escape(str)

Escape the special LaTeX characters in the string +str+.
def escape(str)
  str.gsub(ESCAPE_RE) {|m| ESCAPE_MAP[m]}
end

def initialize(root, options)

Initialize the LaTeX converter with the +root+ element and the conversion +options+.
def initialize(root, options)
  super
  @data[:packages] = Set.new
end

def inner(el, opts)

Return the converted content of the children of +el+ as a string.
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

def latex_environment(type, el, text)

\\end lines of the LaTeX environment for easier post-processing of LaTeX environments.
the method #attribute_list -- the resulting string is appended to both the \\begin and the
Wrap the +text+ inside a LaTeX environment of type +type+. The element +el+ is passed on to
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

def latex_link_target(el, add_label = false)

additionally to the \hypertarget command.
+nil+ otherwise. If the parameter +add_label+ is +true+, a \label command will also be used
Return a string containing a valid \hypertarget command if the element has an ID defined, or
def latex_link_target(el, add_label = false)
  if (id = el.attr['id'])
    "\\hypertarget{#{id}}{}" << (add_label ? "\\label{#{id}}" : '')
  else
    nil
  end
end

def normalize_abbreviation_key(key)

Normalize the abbreviation key so that it only contains allowed ASCII character
def normalize_abbreviation_key(key)
  key.gsub(/\W/) {|m| m.unpack('H*').first}
end