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
33 def initialize(root, options)
34   super
35   @data[:packages] = Set.new
36 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
592 def attribute_list(el)
593   attrs = el.attr.map {|k,v| v.nil? ? '' : " #{k}=\"#{v.to_s}\""}.compact.sort.join('')
594   attrs = "   % #{attrs}" if !attrs.empty?
595   attrs
596 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
40 def convert(el, opts = {})
41   send("convert_#{el.type}", el, opts)
42 end
convert_a(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
209 def convert_a(el, opts)
210   url = el.attr['href']
211   if url.start_with?('#')
212     "\\hyperlink{#{url[1..-1].gsub('%', "\\%")}}{#{inner(el, opts)}}"
213   else
214     "\\href{#{url.gsub('%', "\\%")}}{#{inner(el, opts)}}"
215   end
216 end
convert_abbreviation(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
562 def convert_abbreviation(el, opts)
563   @data[:packages] += %w[acronym]
564   "\\ac{#{normalize_abbreviation_key(el.value)}}"
565 end
convert_blank(el, opts) click to toggle source
   # File lib/kramdown/converter/latex.rb
60 def convert_blank(el, opts)
61   opts[:result] =~ /\n\n\Z|\A\Z/ ? "" : "\n"
62 end
convert_blockquote(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
105 def convert_blockquote(el, opts)
106   latex_environment(el.children.size > 1 ? 'quotation' : 'quote', el, inner(el, opts))
107 end
convert_br(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
203 def convert_br(el, opts)
204   res = "\\newline"
205   res << "\n" if (c = opts[:parent].children[opts[:index]+1]) && (c.type != :text || c.value !~ /^\s*\n/)
206   res
207 end
convert_codeblock(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
 83 def convert_codeblock(el, opts)
 84   show_whitespace = el.attr['class'].to_s =~ /\bshow-whitespaces\b/
 85   lang = extract_code_language(el.attr)
 86 
 87   if @options[:syntax_highlighter] == :minted &&
 88       (highlighted_code = highlight_code(el.value, lang, :block))
 89     @data[:packages] << 'minted'
 90     "#{latex_link_target(el)}#{highlighted_code}\n"
 91   elsif show_whitespace || lang
 92     options = []
 93     options << "showspaces=%s,showtabs=%s" % (show_whitespace ? ['true', 'true'] : ['false', 'false'])
 94     options << "language=#{lang}" if lang
 95     options << "basicstyle=\\ttfamily\\footnotesize,columns=fixed,frame=tlbr"
 96     id = el.attr['id']
 97     options << "label=#{id}" if id
 98     attrs = attribute_list(el)
 99     "#{latex_link_target(el)}\\begin{lstlisting}[#{options.join(',')}]\n#{el.value}\n\\end{lstlisting}#{attrs}\n"
100   else
101     "#{latex_link_target(el)}\\begin{verbatim}#{el.value}\\end{verbatim}\n"
102   end
103 end
convert_codespan(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
232 def convert_codespan(el, opts)
233   lang = extract_code_language(el.attr)
234   if @options[:syntax_highlighter] == :minted &&
235       (highlighted_code = highlight_code(el.value, lang, :span))
236     @data[:packages] << 'minted'
237     "#{latex_link_target(el)}#{highlighted_code}"
238   else
239     "\\texttt{#{latex_link_target(el)}#{escape(el.value)}}"
240   end
241 end
convert_comment(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
199 def convert_comment(el, opts)
200   el.value.split(/\n/).map {|l| "% #{l}"}.join("\n") << "\n"
201 end
convert_dd(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
146 def convert_dd(el, opts)
147   "#{latex_link_target(el)}#{inner(el, opts)}\n\n"
148 end
convert_dl(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
134 def convert_dl(el, opts)
135   latex_environment('description', el, inner(el, opts))
136 end
convert_dt(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
142 def convert_dt(el, opts)
143   "\\item[#{inner(el, opts)}] "
144 end
convert_em(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
256 def convert_em(el, opts)
257   "\\emph{#{latex_link_target(el)}#{inner(el, opts)}}"
258 end
convert_entity(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
526 def convert_entity(el, opts)
527   entity_to_latex(el.value)
528 end
convert_footnote(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
243 def convert_footnote(el, opts)
244   @data[:packages] << 'fancyvrb'
245   "\\footnote{#{inner(el.value, opts).rstrip}}"
246 end
convert_header(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
109 def convert_header(el, opts)
110   type = @options[:latex_headers][output_header_level(el.options[:level]) - 1]
111   if ((id = el.attr['id']) ||
112       (@options[:auto_ids] && (id = generate_id(el.options[:raw_text])))) && in_toc?(el)
113     "\\#{type}{#{inner(el, opts)}}\\hypertarget{#{id}}{}\\label{#{id}}\n\n"
114   else
115     "\\#{type}*{#{inner(el, opts)}}\n\n"
116   end
117 end
convert_hr(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
119 def convert_hr(el, opts)
120   attrs = attribute_list(el)
121   "#{latex_link_target(el)}\\begin{center}#{attrs}\n\\rule{3in}{0.4pt}\n\\end{center}#{attrs}\n"
122 end
convert_html_element(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
150 def convert_html_element(el, opts)
151   if el.value == 'i' || el.value == 'em'
152     "\\emph{#{inner(el, opts)}}"
153   elsif el.value == 'b' || el.value == 'strong'
154     "\\textbf{#{inner(el, opts)}}"
155   else
156     warning("Can't convert HTML element")
157     ''
158   end
159 end
convert_img(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
218 def convert_img(el, opts)
219   line = el.options[:location]
220   if el.attr['src'] =~ /^(https?|ftps?):\/\//
221     warning("Cannot include non-local image#{line ? " (line #{line})" : ''}")
222     ''
223   elsif !el.attr['src'].empty?
224     @data[:packages] << 'graphicx'
225     "#{latex_link_target(el)}\\includegraphics{#{el.attr['src']}}"
226   else
227     warning("Cannot include image with empty path#{line ? " (line #{line})" : ''}")
228     ''
229   end
230 end
convert_li(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
138 def convert_li(el, opts)
139   "\\item{} #{latex_link_target(el, true)}#{inner(el, opts).sub(/\n+\Z/, '')}\n"
140 end
convert_math(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
549 def convert_math(el, opts)
550   @data[:packages] += %w[amssymb amsmath amsthm amsfonts]
551   if el.options[:category] == :block
552     if el.value =~ /\A\s*\\begin\{/
553       el.value
554     else
555       latex_environment('displaymath', el, el.value)
556     end
557   else
558     "$#{el.value}$"
559   end
560 end
convert_ol(el, opts)
Alias for: convert_ul
convert_p(el, opts) click to toggle source
   # File lib/kramdown/converter/latex.rb
68 def convert_p(el, opts)
69   if el.children.size == 1 && el.children.first.type == :img && !(img = convert_img(el.children.first, opts)).empty?
70     convert_standalone_image(el, opts, img)
71   else
72     "#{latex_link_target(el)}#{inner(el, opts)}\n\n"
73   end
74 end
convert_raw(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
248 def convert_raw(el, opts)
249   if !el.options[:type] || el.options[:type].empty? || el.options[:type].include?('latex')
250     el.value + (el.options[:category] == :block ? "\n" : '')
251   else
252     ''
253   end
254 end
convert_root(el, opts) click to toggle source
   # File lib/kramdown/converter/latex.rb
56 def convert_root(el, opts)
57   inner(el, opts)
58 end
convert_smart_quote(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
543 def convert_smart_quote(el, opts)
544   res = entity_to_latex(smart_quote_entity(el)).chomp('{}')
545   res << "{}" if ((nel = opts[:parent].children[opts[:index]+1]) && nel.type == :smart_quote) || res =~ /\w$/
546   res
547 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
78 def convert_standalone_image(el, opts, img)
79   attrs = attribute_list(el)
80   "\\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"
81 end
convert_strong(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
260 def convert_strong(el, opts)
261   "\\textbf{#{latex_link_target(el)}#{inner(el, opts)}}"
262 end
convert_table(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
172 def convert_table(el, opts)
173   @data[:packages] << 'longtable'
174   align = el.options[:alignment].map {|a| TABLE_ALIGNMENT_CHAR[a]}.join('|')
175   attrs = attribute_list(el)
176   "#{latex_link_target(el)}\\begin{longtable}{|#{align}|}#{attrs}\n\\hline\n#{inner(el, opts)}\\hline\n\\end{longtable}#{attrs}\n\n"
177 end
convert_tbody(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
183 def convert_tbody(el, opts)
184   inner(el, opts)
185 end
convert_td(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
195 def convert_td(el, opts)
196   inner(el, opts)
197 end
convert_text(el, opts) click to toggle source
   # File lib/kramdown/converter/latex.rb
64 def convert_text(el, opts)
65   escape(el.value)
66 end
convert_tfoot(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
187 def convert_tfoot(el, opts)
188   "\\hline \\hline \n#{inner(el, opts)}"
189 end
convert_thead(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
179 def convert_thead(el, opts)
180   "#{inner(el, opts)}\\hline\n"
181 end
convert_tr(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
191 def convert_tr(el, opts)
192   el.children.map {|c| send("convert_#{c.type}", c, opts)}.join(' & ') << "\\\\\n"
193 end
convert_typographic_sym(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
535 def convert_typographic_sym(el, opts)
536   if (result = @options[:typographic_symbols][el.value])
537     escape(result)
538   else
539     TYPOGRAPHIC_SYMS[el.value]
540   end
541 end
convert_ul(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
124 def convert_ul(el, opts)
125   if !@data[:has_toc] && (el.options[:ial][:refs].include?('toc') rescue nil)
126     @data[:has_toc] = true
127     '\tableofcontents'
128   else
129     latex_environment(el.type == :ul ? 'itemize' : 'enumerate', el, inner(el, opts))
130   end
131 end
Also aliased as: convert_ol
convert_xml_comment(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
161 def convert_xml_comment(el, opts)
162   el.value.split(/\n/).map {|l| "% #{l}"}.join("\n") + "\n"
163 end
convert_xml_pi(el, opts) click to toggle source
    # File lib/kramdown/converter/latex.rb
165 def convert_xml_pi(el, opts)
166   warning("Can't convert XML PI")
167   ''
168 end
entity_to_latex(entity) click to toggle source
    # File lib/kramdown/converter/latex.rb
515 def entity_to_latex(entity)
516   text, package = ENTITY_CONV_TABLE[entity.code_point]
517   if text
518     @data[:packages] << package if package
519     text
520   else
521     warning("Couldn't find entity with code #{entity.code_point} in substitution table!")
522     ''
523   end
524 end
escape(str) click to toggle source

Escape the special LaTeX characters in the string str.

    # File lib/kramdown/converter/latex.rb
611 def escape(str)
612   str.gsub(ESCAPE_RE) {|m| ESCAPE_MAP[m]}
613 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
45 def inner(el, opts)
46   result = ''
47   options = opts.dup.merge(:parent => el)
48   el.children.each_with_index do |inner_el, index|
49     options[:index] = index
50     options[:result] = result
51     result << send("convert_#{inner_el.type}", inner_el, options)
52   end
53   result
54 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
575 def latex_environment(type, el, text)
576   attrs = attribute_list(el)
577   "\\begin{#{type}}#{latex_link_target(el)}#{attrs}\n#{text.rstrip}\n\\end{#{type}}#{attrs}\n"
578 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
568 def normalize_abbreviation_key(key)
569   key.gsub(/\W/) {|m| m.unpack('H*').first}
570 end