require'yaml'moduleRedCloth::Formatters::LATEXincludeRedCloth::Formatters::Basedefself.entities@entities||=YAML.load(File.read(File.dirname(__FILE__)+'/latex_entities.yml'))endmoduleSettings# Maps CSS style names to latex formatting optionsdeflatex_image_styles@latex_image_class_styles||={}endendRedCloth::TextileDoc.send(:include,Settings)# headers{:h1=>'section',:h2=>'subsection',:h3=>'subsubsection',:h4=>'paragraph',:h5=>'subparagraph',:h6=>'textbf',}.eachdo|m,tag|define_method(m)do|opts|caseopts[:align]when'left'then"\\begin{flushleft}\\#{tag}{#{opts[:text]}}\\end{flushleft}\n\n"when'right'then"\\begin{flushright}\\#{tag}{#{opts[:text]}}\\end{flushright}\n\n"when'center'then"\\begin{center}\\#{tag}{#{opts[:text]}}\\end{center}\n\n"else"\\#{tag}{#{opts[:text]}}\n\n"endendend# commands {:strong=>'textbf',:em=>'emph',:i=>'textit',:b=>'textbf',:ins=>'underline',:del=>'sout',}.eachdo|m,tag|define_method(m)do|opts|"\\#{tag}{#{opts[:text]}}"endend# inline codedefcode(opts)opts[:block]?opts[:text]:"\\verb@#{opts[:text]}@"end# acronymsdefacronym(opts)"#{opts[:title]} (#{opts[:text]})"end# sub/superscripts{:sup=>'\textsuperscript{#1}',:sub=>'\textsubscript{#1}',}.eachdo|m,expr|define_method(m)do|opts|expr.sub('#1',opts[:text])endend# environments{:pre=>'verbatim',:cite=>'quote',}.eachdo|m,env|define_method(m)do|opts|begin_chunk(env)+opts[:text]+end_chunk(env)endend# ignore (or find a good solution later)[:span,:div,:caps].eachdo|m|define_method(m)do|opts|opts[:text].to_sendend# lists{:ol=>'enumerate',:ul=>'itemize',}.eachdo|m,env|define_method("#{m}_open")do|opts|opts[:block]=true"\\begin{#{env}}\n"enddefine_method("#{m}_close")do|opts|"\\end{#{env}}\n\n"endenddefli_open(opts)" \\item #{opts[:text]}"enddefli_close(opts=nil)"\n"end# paragraphsdefp(opts)caseopts[:align]when'left'then"\\begin{flushleft}#{opts[:text]}\\end{flushleft}\n\n"when'right'then"\\begin{flushright}#{opts[:text]}\\end{flushright}\n\n"when'center'then"\\begin{center}#{opts[:text]}\\end{center}\n\n"else"#{opts[:text]}\n\n"endend# tablesdeftd(opts)column=@table_row.sizeifopts[:colspan]opts[:text]="\\multicolumn{#{opts[:colspan]}}{ #{"l "*opts[:colspan].to_i}}{#{opts[:text]}}"endifopts[:rowspan]@table_multirow_next[column]=opts[:rowspan].to_i-1opts[:text]="\\multirow{#{opts[:rowspan]}}{*}{#{opts[:text]}}"end@table_row.push(opts[:text])return""enddeftr_open(opts)@table_row=[]return""enddeftr_close(opts)multirow_columns=@table_multirow.find_all{|c,n|n>0}multirow_columns.eachdo|c,n|@table_row.insert(c,"")@table_multirow[c]-=1end@table_multirow.merge!(@table_multirow_next)@table_multirow_next={}@table.push(@table_row)return""end# We need to know the column count before opening tabular context.deftable_open(opts)@table=[]@table_multirow={}@table_multirow_next={}return""end# FIXME: need caption and label elements similar to image -> figuredeftable_close(opts)output="\\begin{table}\n".dupoutput<<" \\centering\n"output<<" \\begin{tabular}{ #{"l "*@table[0].size}}\n"@table.eachdo|row|output<<" #{row.join(" & ")}\\\\\n"endoutput<<" \\end{tabular}\n"output<<"\\end{table}\n"outputend# code blocksdefbc_open(opts)opts[:block]=truebegin_chunk("verbatim")+"\n"enddefbc_close(opts)end_chunk("verbatim")+"\n"end# block quotationsdefbq_open(opts)opts[:block]=true"\\begin{quotation}\n"enddefbq_close(opts)"\\end{quotation}\n\n"end# linksdeflink(opts)"\\href{#{opts[:href]}}{#{opts[:name]}}"end# FIXME: use includegraphics with security verification## Remember to use '\RequirePackage{graphicx}' in your LaTeX header# # FIXME: Look at dealing with width / height gracefully as this should be # specified in a unit like cm rather than px.defimage(opts)# Don't know how to use remote links, plus can we trust them?return""ifopts[:src]=~/^\w+\:\/\//# Resolve CSS styles if any have been setstyling=opts[:class].to_s.split(/\s+/).collect{|style|latex_image_styles[style]}.compact.join','# Build latex code["\\begin{figure}"," \\centering"," \\includegraphics[#{styling}]{#{opts[:src]}}",(" \\caption{#{escapeopts[:title]}}"ifopts[:title]),(" \\label{#{escapeopts[:alt]}}"ifopts[:alt]),"\\end{figure}",].compact.join"\n"end# footnotesdeffootno(opts)# TODO: insert a placeholder until we know the footnote content.# For this to work, we need some kind of post-processing..."\\footnotemark[#{opts[:text]}]"enddeffn(opts)"\\footnotetext[#{opts[:id]}]{#{opts[:text]}}"end# inline verbatimdefsnip(opts)"\\verb`#{opts[:text]}`"enddefquote1(opts)"`#{opts[:text]}'"enddefquote2(opts)"``#{opts[:text]}''"enddefellipsis(opts)"#{opts[:text]}\\ldots{}"enddefemdash(opts)"---"enddefendash(opts)" -- "enddefarrow(opts)"\\rightarrow{}"enddeftrademark(opts)"\\texttrademark{}"enddefregistered(opts)"\\textregistered{}"enddefcopyright(opts)"\\copyright{}"end# TODO: what do we do with (unknown) unicode entities ? #defentity(opts)text=opts[:text][0..0]=='#'?opts[:text][1..-1]:opts[:text]RedCloth::Formatters::LATEX.entities[text]enddefdim(opts)opts[:text].gsub!('x','\times')opts[:text].gsub!('"',"''")period=opts[:text].slice!(/\.$/)"$#{opts[:text]}$#{period}"end# TODO: what do we do with HTML?definline_html(opts)opts[:text]||""endprivatedefescape(text)latex_esc(text)enddefescape_pre(text)textend# Use this for block level commands that use \begindefbegin_chunk(type)chunk_counter[type]+=1return"\\begin{#{type}}"if1==chunk_counter[type]''end# Use this for block level commands that use \enddefend_chunk(type)chunk_counter[type]-=1raiseRuntimeError,"Bad latex #{type} nesting detected"ifchunk_counter[type]<0# This should never need to happenreturn"\\end{#{type}}"if0==chunk_counter[type]''enddefchunk_counter@chunk_counter||=Hash.new0endend