require 'md2man/document' module Md2Man::Roff include Md2Man::Document #--------------------------------------------------------------------------- # document-level processing #--------------------------------------------------------------------------- def preprocess document @ordered_list_id = 0 @table_cells = {} @h1_seen = false super end def postprocess document super.strip. # ensure that spaces after URLs appear properly gsub(/(^\.[UM]E) \s/, "\\1\n"). # squeeze blank lines to prevent double-spaced output gsub(/^\n/, '') end #--------------------------------------------------------------------------- # block-level processing #--------------------------------------------------------------------------- def indented_paragraph text "\n.IP\n#{text}\n" end def tagged_paragraph text "\n.TP\n#{text}\n" end def normal_paragraph text "\n.PP\n#{text}\n" end def block_code code, language code = escape(code, true) block_quote "\n.nf\n#{code.chomp}\n.fi\n" end def block_quote quote "\n.PP\n.RS\n#{remove_leading_pp(quote).chomp}\n.RE\n" end def block_html html warn "md2man/roff: block_html not implemented: #{html.inspect}" end def header text, level, _=nil macro = case level when 1 if @h1_seen :SH else @h1_seen = true :TH end when 2 then :SH else :SS end "\n.#{macro} #{text.chomp}\n" end def hrule "\n.ti 0\n\\l'\\n(.lu'\n" end def list contents, list_type result = [] if list_type == :ordered result << ".nr step#{@ordered_list_id} 0 1" @ordered_list_id += 1 end result << ".RS\n#{contents}\n.RE\n" result.join("\n") end def list_item text, list_type designator = case list_type when :ordered "\\n+[step#{@ordered_list_id}]" when :unordered "\\(bu 2" end ".IP #{designator}\n#{remove_leading_pp(text).lstrip.chomp}\n" end def table header, body head_rows = decode_table_rows(header) body_rows = decode_table_rows(body) ".TS\nallbox;\n#{ [ head_rows.map do |row| (['cb'] * row.length).join(TABLE_COL_DELIM) end, body_rows.map do |row| row.map do |content, alignment| (alignment || :left).to_s[0,1] end.join(TABLE_COL_DELIM) end ].join(TABLE_ROW_DELIM) }\n.\n#{ (head_rows + body_rows).map do |row| row.map(&:first).join(TABLE_CELL_DELIM) end.join(TABLE_ROW_DELIM) }\n.TE\n" end def table_row content encode_table_row content end def table_cell content, alignment encode_table_cell [content, alignment] end #--------------------------------------------------------------------------- # span-level processing #--------------------------------------------------------------------------- def reference input_match, output_match "\n.BR #{input_match[:page]} (#{input_match[:section]})#{output_match[:addendum]}\n" end def linebreak "\n.br\n" end def emphasis text "\\fI#{text}\\fP" end def double_emphasis text "\\fB#{text}\\fP" end def triple_emphasis text "\\s+2#{double_emphasis text}\\s-2" end def strikethrough text warn "md2man/roff: strikethrough not implemented: #{text.inspect}" end def superscript text warn "md2man/roff: superscript not implemented: #{text.inspect}" end def codespan code code = escape(code, true) # NOTE: this double font sequence gives us the best of both worlds: # man(1) shows it in bold and `groff -Thtml` shows it in monospace "\\fB\\fC#{code}\\fR" end def link link, title, content content + if link =~ /^mailto:/ autolink $', :email else autolink link, :url end end def autolink link, link_type if link_type == :email "\n.MT #{link.chomp}\n.ME " else "\n.UR #{link.chomp}\n.UE " end end def image link, title, alt_text warn "md2man/roff: image not implemented: #{link.inspect}" end def raw_html html warn "md2man/roff: raw_html not implemented: #{html.inspect}" end #--------------------------------------------------------------------------- # low-level processing #--------------------------------------------------------------------------- def normal_text text escape text, false if text end def entity text if unicode = entity_to_unicode(text) unicode_to_glyph unicode else warn "md2man/roff: entity not implemented: #{text.inspect}" end end private def escape text, literally if text then text. # escape backslashes so that they appear in the printable output gsub('\\', literally ? '\&\&' : '\\[rs]'). # escape soft-hyphens so that they appear in the printable output gsub('-', '\\-'). # escape line-beginning control characters (period and single quote) # by prefixing a non-printable, zero-width glyph (backslash ampersand) gsub(/^(?=[.'])/, '\\\\&') end end def remove_leading_pp text text.sub(/\A\n\.PP\n/, '') end TABLE_COL_DELIM = ' ' TABLE_ROW_DELIM = "\n" TABLE_CELL_DELIM = "\t" def decode_table_rows rows rows.split(TABLE_ROW_DELIM).map do |row| row.split(TABLE_CELL_DELIM).map do |cell| @table_cells.delete cell end end end def encode_table_row row row + TABLE_ROW_DELIM end def encode_table_cell cell key = encode(cell) @table_cells[key] = cell key + TABLE_CELL_DELIM end def entity_to_unicode entity if ENTITY_TO_UNICODE.key? entity ENTITY_TO_UNICODE[entity] elsif entity =~ /^&#(\d+);$/ $1.to_i elsif entity =~ /^&#x(\h+);$/ $1.to_i(16) end end def unicode_to_glyph unicode if UNICODE_TO_GLYPH.key? unicode UNICODE_TO_GLYPH[unicode] elsif unicode < 256 '\\[char%d]' % unicode else '\\[u%04x]' % unicode end end # see http://www.w3.org/TR/xhtml1/dtds.html#h-A2 # see http://www.w3.org/TR/html4/sgml/entities.html ENTITY_TO_UNICODE = { '"' => 0x0022, '&' => 0x0026, ''' => 0x0027, '<' => 0x003c, '>' => 0x003e, ' ' => 0x00a0, '¡' => 0x00a1, '¢' => 0x00a2, '£' => 0x00a3, '¤' => 0x00a4, '¥' => 0x00a5, '¦' => 0x00a6, '§' => 0x00a7, '¨' => 0x00a8, '©' => 0x00a9, 'ª' => 0x00aa, '«' => 0x00ab, '¬' => 0x00ac, '­' => 0x00ad, '®' => 0x00ae, '¯' => 0x00af, '°' => 0x00b0, '±' => 0x00b1, '²' => 0x00b2, '³' => 0x00b3, '´' => 0x00b4, 'µ' => 0x00b5, '¶' => 0x00b6, '·' => 0x00b7, '¸' => 0x00b8, '¹' => 0x00b9, 'º' => 0x00ba, '»' => 0x00bb, '¼' => 0x00bc, '½' => 0x00bd, '¾' => 0x00be, '¿' => 0x00bf, 'À' => 0x00c0, 'Á' => 0x00c1, 'Â' => 0x00c2, 'Ã' => 0x00c3, 'Ä' => 0x00c4, 'Å' => 0x00c5, 'Æ' => 0x00c6, 'Ç' => 0x00c7, 'È' => 0x00c8, 'É' => 0x00c9, 'Ê' => 0x00ca, 'Ë' => 0x00cb, 'Ì' => 0x00cc, 'Í' => 0x00cd, 'Î' => 0x00ce, 'Ï' => 0x00cf, 'Ð' => 0x00d0, 'Ñ' => 0x00d1, 'Ò' => 0x00d2, 'Ó' => 0x00d3, 'Ô' => 0x00d4, 'Õ' => 0x00d5, 'Ö' => 0x00d6, '×' => 0x00d7, 'Ø' => 0x00d8, 'Ù' => 0x00d9, 'Ú' => 0x00da, 'Û' => 0x00db, 'Ü' => 0x00dc, 'Ý' => 0x00dd, 'Þ' => 0x00de, 'ß' => 0x00df, 'à' => 0x00e0, 'á' => 0x00e1, 'â' => 0x00e2, 'ã' => 0x00e3, 'ä' => 0x00e4, 'å' => 0x00e5, 'æ' => 0x00e6, 'ç' => 0x00e7, 'è' => 0x00e8, 'é' => 0x00e9, 'ê' => 0x00ea, 'ë' => 0x00eb, 'ì' => 0x00ec, 'í' => 0x00ed, 'î' => 0x00ee, 'ï' => 0x00ef, 'ð' => 0x00f0, 'ñ' => 0x00f1, 'ò' => 0x00f2, 'ó' => 0x00f3, 'ô' => 0x00f4, 'õ' => 0x00f5, 'ö' => 0x00f6, '÷' => 0x00f7, 'ø' => 0x00f8, 'ù' => 0x00f9, 'ú' => 0x00fa, 'û' => 0x00fb, 'ü' => 0x00fc, 'ý' => 0x00fd, 'þ' => 0x00fe, 'ÿ' => 0x00ff, 'Œ' => 0x0152, 'œ' => 0x0153, 'Š' => 0x0160, 'š' => 0x0161, 'Ÿ' => 0x0178, 'ƒ' => 0x0192, 'ˆ' => 0x02c6, '˜' => 0x02dc, 'Α' => 0x0391, 'Β' => 0x0392, 'Γ' => 0x0393, 'Δ' => 0x0394, 'Ε' => 0x0395, 'Ζ' => 0x0396, 'Η' => 0x0397, 'Θ' => 0x0398, 'Ι' => 0x0399, 'Κ' => 0x039a, 'Λ' => 0x039b, 'Μ' => 0x039c, 'Ν' => 0x039d, 'Ξ' => 0x039e, 'Ο' => 0x039f, 'Π' => 0x03a0, 'Ρ' => 0x03a1, 'Σ' => 0x03a3, 'Τ' => 0x03a4, 'Υ' => 0x03a5, 'Φ' => 0x03a6, 'Χ' => 0x03a7, 'Ψ' => 0x03a8, 'Ω' => 0x03a9, 'α' => 0x03b1, 'β' => 0x03b2, 'γ' => 0x03b3, 'δ' => 0x03b4, 'ε' => 0x03b5, 'ζ' => 0x03b6, 'η' => 0x03b7, 'θ' => 0x03b8, 'ι' => 0x03b9, 'κ' => 0x03ba, 'λ' => 0x03bb, 'μ' => 0x03bc, 'ν' => 0x03bd, 'ξ' => 0x03be, 'ο' => 0x03bf, 'π' => 0x03c0, 'ρ' => 0x03c1, 'ς' => 0x03c2, 'σ' => 0x03c3, 'τ' => 0x03c4, 'υ' => 0x03c5, 'φ' => 0x03c6, 'χ' => 0x03c7, 'ψ' => 0x03c8, 'ω' => 0x03c9, 'ϑ' => 0x03d1, 'ϒ' => 0x03d2, 'ϖ' => 0x03d6, ' ' => 0x2002, ' ' => 0x2003, ' ' => 0x2009, '‌' => 0x200c, '‍' => 0x200d, '‎' => 0x200e, '‏' => 0x200f, '–' => 0x2013, '—' => 0x2014, '‘' => 0x2018, '’' => 0x2019, '‚' => 0x201a, '“' => 0x201c, '”' => 0x201d, '„' => 0x201e, '†' => 0x2020, '‡' => 0x2021, '•' => 0x2022, '…' => 0x2026, '‰' => 0x2030, '′' => 0x2032, '″' => 0x2033, '‹' => 0x2039, '›' => 0x203a, '‾' => 0x203e, '⁄' => 0x2044, '€' => 0x20ac, 'ℑ' => 0x2111, '℘' => 0x2118, 'ℜ' => 0x211c, '™' => 0x2122, 'ℵ' => 0x2135, '←' => 0x2190, '↑' => 0x2191, '→' => 0x2192, '↓' => 0x2193, '↔' => 0x2194, '↵' => 0x21b5, '⇐' => 0x21d0, '⇑' => 0x21d1, '⇒' => 0x21d2, '⇓' => 0x21d3, '⇔' => 0x21d4, '∀' => 0x2200, '∂' => 0x2202, '∃' => 0x2203, '∅' => 0x2205, '∇' => 0x2207, '∈' => 0x2208, '∉' => 0x2209, '∋' => 0x220b, '∏' => 0x220f, '∑' => 0x2211, '−' => 0x2212, '∗' => 0x2217, '√' => 0x221a, '∝' => 0x221d, '∞' => 0x221e, '∠' => 0x2220, '∧' => 0x2227, '∨' => 0x2228, '∩' => 0x2229, '∪' => 0x222a, '∫' => 0x222b, '∴' => 0x2234, '∼' => 0x223c, '≅' => 0x2245, '≈' => 0x2248, '≠' => 0x2260, '≡' => 0x2261, '≤' => 0x2264, '≥' => 0x2265, '⊂' => 0x2282, '⊃' => 0x2283, '⊄' => 0x2284, '⊆' => 0x2286, '⊇' => 0x2287, '⊕' => 0x2295, '⊗' => 0x2297, '⊥' => 0x22a5, '⋅' => 0x22c5, '⌈' => 0x2308, '⌉' => 0x2309, '⌊' => 0x230a, '⌋' => 0x230b, '⟨' => 0x2329, '⟩' => 0x232a, '◊' => 0x25ca, '♠' => 0x2660, '♣' => 0x2663, '♥' => 0x2665, '♦' => 0x2666, } # see groff_char(7) and "Special Characters" in groff(7) UNICODE_TO_GLYPH = { 0x0022 => '\\[dq]', 0x0023 => '\\[sh]', 0x0024 => '\\[Do]', 0x0026 => '&', 0x0027 => '\\[aq]', 0x002b => '\\[pl]', 0x002f => '\\[sl]', 0x003c => '<', 0x003d => '\\[eq]', 0x003e => '>', 0x0040 => '\\[at]', 0x005b => '\\[lB]', 0x005c => '\\[rs]', 0x005d => '\\[rB]', 0x005e => '\\[ha]', 0x005f => '\\[nl]', 0x007b => '\\[lC]', 0x007c => '\\[ba]', #0x007c => '\\[or]', 0x007d => '\\[rC]', 0x007e => '\\[ti]', 0x00a0 => '\\~', 0x00a1 => '\\[r!]', 0x00a2 => '\\[ct]', 0x00a3 => '\\[Po]', 0x00a4 => '\\[Cs]', 0x00a5 => '\\[Ye]', 0x00a6 => '\\[bb]', 0x00a7 => '\\[sc]', 0x00a8 => '\\[ad]', 0x00a9 => '\\[co]', 0x00aa => '\\[Of]', 0x00ab => '\\[Fo]', 0x00ac => '\\[no]', #0x00ac => '\\[tno]', 0x00ad => '-', 0x00ae => '\\[rg]', 0x00af => '\\[a-]', 0x00b0 => '\\[de]', 0x00b1 => '\\[+-]', #0x00b1 => '\\[t+-]', 0x00b2 => '\\[S2]', 0x00b3 => '\\[S3]', 0x00b4 => '\\[aa]', 0x00b5 => '\\[mc]', 0x00b6 => '\\[ps]', 0x00b7 => '\\[pc]', 0x00b8 => '\\[ac]', 0x00b9 => '\\[S1]', 0x00ba => '\\[Om]', 0x00bb => '\\[Fc]', 0x00bc => '\\[14]', 0x00bd => '\\[12]', 0x00be => '\\[34]', 0x00bf => '\\[r?]', 0x00c0 => '\\[`A]', 0x00c1 => '\\[\'A]', 0x00c2 => '\\[^A]', 0x00c3 => '\\[~A]', 0x00c4 => '\\[:A]', 0x00c5 => '\\[oA]', 0x00c6 => '\\[AE]', 0x00c7 => '\\[,C]', 0x00c8 => '\\[`E]', 0x00c9 => '\\[\'E]', 0x00ca => '\\[^E]', 0x00cb => '\\[:E]', 0x00cc => '\\[`I]', 0x00cd => '\\[\'I]', 0x00ce => '\\[^I]', 0x00cf => '\\[:I]', 0x00d0 => '\\[-D]', 0x00d1 => '\\[~N]', 0x00d2 => '\\[`O]', 0x00d3 => '\\[\'O]', 0x00d4 => '\\[^O]', 0x00d5 => '\\[~O]', 0x00d6 => '\\[:O]', 0x00d7 => '\\[mu]', #0x00d7 => '\\[tmu]', 0x00d8 => '\\[/O]', 0x00d9 => '\\[`U]', 0x00da => '\\[\'U]', 0x00db => '\\[^U]', 0x00dc => '\\[:U]', 0x00dd => '\\[\'Y]', 0x00de => '\\[TP]', 0x00df => '\\[ss]', 0x00e0 => '\\[`a]', 0x00e1 => '\\[\'a]', 0x00e2 => '\\[^a]', 0x00e3 => '\\[~a]', 0x00e4 => '\\[:a]', 0x00e5 => '\\[oa]', 0x00e6 => '\\[ae]', 0x00e7 => '\\[,c]', 0x00e8 => '\\[`e]', 0x00e9 => '\\[\'e]', 0x00ea => '\\[^e]', 0x00eb => '\\[:e]', 0x00ec => '\\[`i]', 0x00ed => '\\[\'i]', 0x00ee => '\\[^i]', 0x00ef => '\\[:i]', 0x00f0 => '\\[Sd]', 0x00f1 => '\\[~n]', 0x00f2 => '\\[`o]', 0x00f3 => '\\[\'o]', 0x00f4 => '\\[^o]', 0x00f5 => '\\[~o]', 0x00f6 => '\\[:o]', 0x00f7 => '\\[di]', #0x00f7 => '\\[tdi]', 0x00f8 => '\\[/o]', 0x00f9 => '\\[`u]', 0x00fa => '\\[\'u]', 0x00fb => '\\[^u]', 0x00fc => '\\[:u]', 0x00fd => '\\[\'y]', 0x00fe => '\\[Tp]', 0x00ff => '\\[:y]', 0x0131 => '\\[.i]', 0x0132 => '\\[IJ]', 0x0133 => '\\[ij]', 0x0141 => '\\[/L]', 0x0142 => '\\[/l]', 0x0152 => '\\[OE]', 0x0153 => '\\[oe]', 0x0160 => '\\[vS]', 0x0161 => '\\[vs]', 0x0178 => '\\[:Y]', 0x0192 => '\\[Fn]', 0x02c6 => '\\[a^]', 0x02dc => '\\[a~]', 0x0300 => '\\[ga]', 0x0301 => '\\[aa]', 0x0302 => '\\[a^]', 0x0303 => '\\[a~]', 0x0304 => '\\[a-]', 0x0306 => '\\[ab]', 0x0307 => '\\[a.]', 0x0308 => '\\[ad]', 0x030a => '\\[ao]', 0x030b => '\\[a"]', 0x030c => '\\[ah]', 0x0327 => '\\[ac]', 0x0328 => '\\[ho]', 0x0391 => '\\[*A]', 0x0392 => '\\[*B]', 0x0393 => '\\[*G]', 0x0394 => '\\[*D]', 0x0395 => '\\[*E]', 0x0396 => '\\[*Z]', 0x0397 => '\\[*Y]', 0x0398 => '\\[*H]', 0x0399 => '\\[*I]', 0x039a => '\\[*K]', 0x039b => '\\[*L]', 0x039c => '\\[*M]', 0x039d => '\\[*N]', 0x039e => '\\[*C]', 0x039f => '\\[*O]', 0x03a0 => '\\[*P]', 0x03a1 => '\\[*R]', 0x03a3 => '\\[*S]', 0x03a4 => '\\[*T]', 0x03a5 => '\\[*U]', 0x03a6 => '\\[*F]', 0x03a7 => '\\[*X]', 0x03a8 => '\\[*Q]', 0x03a9 => '\\[*W]', 0x03b1 => '\\[*a]', 0x03b2 => '\\[*b]', 0x03b3 => '\\[*g]', 0x03b4 => '\\[*d]', 0x03b5 => '\\[*e]', 0x03b6 => '\\[*z]', 0x03b7 => '\\[*y]', 0x03b8 => '\\[*h]', 0x03b9 => '\\[*i]', 0x03ba => '\\[*k]', 0x03bb => '\\[*l]', 0x03bc => '\\[*m]', 0x03bd => '\\[*n]', 0x03be => '\\[*c]', 0x03bf => '\\[*o]', 0x03c0 => '\\[*p]', 0x03c1 => '\\[*r]', 0x03c2 => '\\[ts]', 0x03c3 => '\\[*s]', 0x03c4 => '\\[*t]', 0x03c5 => '\\[*u]', 0x03c6 => '\\[+f]', 0x03c7 => '\\[*x]', 0x03c8 => '\\[*q]', 0x03c9 => '\\[*w]', 0x03d1 => '\\[+h]', 0x03d5 => '\\[*f]', 0x03d6 => '\\[+p]', 0x03f5 => '\\[+e]', 0x2010 => '\\[hy]', 0x2013 => '\\[en]', 0x2014 => '\\[em]', 0x2018 => '\\[oq]', 0x2019 => '\\[cq]', 0x201a => '\\[bq]', 0x201c => '\\[lq]', 0x201d => '\\[rq]', 0x201e => '\\[Bq]', 0x2020 => '\\[dg]', 0x2021 => '\\[dd]', 0x2022 => '\\[bu]', 0x2030 => '\\[%0]', 0x2032 => '\\[fm]', 0x2033 => '\\[sd]', 0x2039 => '\\[fo]', 0x203a => '\\[fc]', 0x203e => '\\[rn]', 0x2044 => '\\[f/]', #0x20ac => '\\[Eu]', 0x20ac => '\\[eu]', 0x210f => '\\[-h]', #0x210f => '\\[hbar]', 0x2111 => '\\[Im]', 0x2118 => '\\[wp]', 0x211c => '\\[Re]', 0x2122 => '\\[tm]', 0x2135 => '\\[Ah]', 0x215b => '\\[18]', 0x215c => '\\[38]', 0x215d => '\\[58]', 0x215e => '\\[78]', 0x2190 => '\\[<-]', 0x2191 => '\\[ua]', 0x2192 => '\\[->]', 0x2193 => '\\[da]', 0x2194 => '\\[<>]', 0x2195 => '\\[va]', 0x21b5 => '\\[CR]', 0x21d0 => '\\[lA]', 0x21d1 => '\\[uA]', 0x21d2 => '\\[rA]', 0x21d3 => '\\[dA]', 0x21d4 => '\\[hA]', 0x21d5 => '\\[vA]', 0x2200 => '\\[fa]', 0x2202 => '\\[pd]', 0x2203 => '\\[te]', 0x2205 => '\\[es]', 0x2207 => '\\[gr]', 0x2208 => '\\[mo]', 0x2209 => '\\[nm]', 0x220b => '\\[st]', 0x220f => '\\[product]', 0x2210 => '\\[coproduct]', 0x2211 => '\\[sum]', 0x2212 => '\\[mi]', 0x2213 => '\\[-+]', 0x2217 => '\\[**]', #0x221a => '\\[sqrt]', 0x221a => '\\[sr]', 0x221d => '\\[pt]', 0x221e => '\\[if]', 0x2220 => '\\[/_]', 0x2227 => '\\[AN]', 0x2228 => '\\[OR]', 0x2229 => '\\[ca]', 0x222a => '\\[cu]', #0x222b => '\\[integral]', 0x222b => '\\[is]', 0x2234 => '\\[3d]', #0x2234 => '\\[tf]', 0x223c => '\\[ap]', 0x2243 => '\\[|=]', 0x2245 => '\\[=~]', #0x2248 => '\\[~=]', 0x2248 => '\\[~~]', 0x2260 => '\\[!=]', 0x2261 => '\\[==]', 0x2264 => '\\[<=]', 0x2265 => '\\[>=]', 0x226a => '\\[<<]', 0x226b => '\\[>>]', 0x2282 => '\\[sb]', 0x2283 => '\\[sp]', 0x2284 => '\\[nb]', 0x2286 => '\\[ib]', 0x2287 => '\\[ip]', 0x2295 => '\\[c+]', 0x2297 => '\\[c*]', 0x22a5 => '\\[pp]', 0x22c5 => '\\[md]', 0x2308 => '\\[lc]', 0x2309 => '\\[rc]', 0x230a => '\\[lf]', 0x230b => '\\[rf]', 0x2329 => '\\[la]', 0x232a => '\\[ra]', 0x239b => '\\[parenlefttp]', 0x239c => '\\[parenleftex]', 0x239d => '\\[parenleftbt]', 0x239e => '\\[parenrighttp]', 0x239f => '\\[parenrightex]', 0x23a0 => '\\[parenrightbt]', 0x23a1 => '\\[bracketlefttp]', 0x23a2 => '\\[bracketleftex]', 0x23a3 => '\\[bracketleftbt]', 0x23a4 => '\\[bracketrighttp]', 0x23a5 => '\\[bracketrightex]', 0x23a6 => '\\[bracketrightbt]', #0x23a7 => '\\[bracelefttp]', 0x23a7 => '\\[lt]', #0x23a8 => '\\[braceleftmid]', 0x23a8 => '\\[lk]', #0x23a9 => '\\[braceleftbt]', 0x23a9 => '\\[lb]', #0x23aa => '\\[braceex]', #0x23aa => '\\[braceleftex]', #0x23aa => '\\[bracerightex]', 0x23aa => '\\[bv]', #0x23ab => '\\[bracerighttp]', 0x23ab => '\\[rt]', #0x23ac => '\\[bracerightmid]', 0x23ac => '\\[rk]', #0x23ad => '\\[bracerightbt]', 0x23ad => '\\[rb]', 0x23af => '\\[an]', 0x2502 => '\\[br]', 0x25a1 => '\\[sq]', 0x25ca => '\\[lz]', 0x25cb => '\\[ci]', 0x261c => '\\[lh]', 0x261e => '\\[rh]', 0x2660 => '\\[SP]', 0x2663 => '\\[CL]', 0x2665 => '\\[HE]', 0x2666 => '\\[DI]', 0x2713 => '\\[OK]', 0x27e8 => '\\[la]', 0x27e9 => '\\[ra]', } end