Class: Fatty::AnsiRenderer
- Inherits:
-
Redcarpet::Render::Base
- Object
- Redcarpet::Render::Base
- Fatty::AnsiRenderer
- Defined in:
- lib/fatty/markdown/ansi_renderer.rb
Constant Summary collapse
- HARD_BREAK =
"\uE000"- CELL_SEP =
"\u001F"- TABLE_BAR =
"│"- TABLE_DASH =
"─"
Instance Method Summary collapse
- #autolink(link, _link_type) ⇒ Object
- #block_code(code, language) ⇒ Object
- #block_quote(quote) ⇒ Object
- #codespan(code) ⇒ Object
- #double_emphasis(text) ⇒ Object
-
#emphasis(text) ⇒ Object
Curses does not reliably render true italics, so we use underline instead.
- #h1(text) ⇒ Object
- #h2(text) ⇒ Object
- #h3(text) ⇒ Object
- #header(text, level) ⇒ Object
- #highlight(text) ⇒ Object
- #hrule ⇒ Object
- #indent_block(text, prefix) ⇒ Object
-
#initialize(width: 80, palette: nil) ⇒ AnsiRenderer
constructor
A new instance of AnsiRenderer.
- #inline(text) ⇒ Object
- #linebreak ⇒ Object
- #link(link, _title, content) ⇒ Object
- #list(contents, _type) ⇒ Object
- #list_item(text, _type) ⇒ Object
- #normal_text(text) ⇒ Object
- #pad_visible(text, width) ⇒ Object
- #paragraph(text) ⇒ Object
- #quote(text) ⇒ Object
- #raw_html(html) ⇒ Object
- #render_inline_html(text) ⇒ Object
- #render_table_row_cells(row, widths, header: false) ⇒ Object
- #render_table_separator(widths) ⇒ Object
- #rouge_lexer(language, code) ⇒ Object
-
#strikethrough(text) ⇒ Object
Curses does not support strike-through, but this emulates it with unicode "combining characters" by adding a "Long Stroke Overlay" (U+0366) after each character, which overlays each with a strike-through overlay.
- #table(header, body) ⇒ Object
- #table_cell(content, _alignment) ⇒ Object
- #table_row(content) ⇒ Object
- #table_widths(rows) ⇒ Object
- #td(text) ⇒ Object
- #th(text) ⇒ Object
Constructor Details
#initialize(width: 80, palette: nil) ⇒ AnsiRenderer
Returns a new instance of AnsiRenderer.
10 11 12 13 14 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 10 def initialize(width: 80, palette: nil) super() @width = width.to_i @palette = palette || {} end |
Instance Method Details
#autolink(link, _link_type) ⇒ Object
82 83 84 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 82 def autolink(link, _link_type) md(link.to_s, :markdown_link) end |
#block_code(code, language) ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 16 def block_code(code, language) lexer = rouge_lexer(language.to_s, code.to_s) formatter = Rouge::Formatters::Terminal256.new gutter = md("│ ", :markdown_code_gutter) highlighted = formatter.format(lexer.lex(code.to_s)) lines = highlighted.lines.map(&:chomp) lines.pop while lines.any? && Fatty::Ansi.plain_text(lines.last).strip.empty? body = lines.map { |line| "#{gutter}#{line}" }.join("\n") "#{body}\n\n" end |
#block_quote(quote) ⇒ Object
90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 90 def block_quote(quote) gutter = md("│ ", :markdown_quote_gutter) quote = CGI.unescapeHTML(quote.to_s) paragraphs = quote.to_s.split(/\n{2,}/).map do |para| text = para.lines.map(&:strip).reject(&:empty?).join(" ") if text.empty? gutter else wrap(text, first_prefix: gutter, rest_prefix: gutter) end end paragraphs.join("\n#{gutter}\n") + "\n\n" end |
#codespan(code) ⇒ Object
65 66 67 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 65 def codespan(code) md(code.to_s, :markdown_code) end |
#double_emphasis(text) ⇒ Object
69 70 71 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 69 def double_emphasis(text) md(text.to_s, :markdown_strong) end |
#emphasis(text) ⇒ Object
Curses does not reliably render true italics, so we use underline instead.
74 75 76 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 74 def emphasis(text) md(text.to_s, :markdown_emphasis) end |
#h1(text) ⇒ Object
239 240 241 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 239 def h1(text) md(text.to_s, :markdown_h1) end |
#h2(text) ⇒ Object
243 244 245 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 243 def h2(text) md(text.to_s, :markdown_h2) end |
#h3(text) ⇒ Object
247 248 249 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 247 def h3(text) md(text.to_s, :markdown_h3) end |
#header(text, level) ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 105 def header(text, level) body = case level when 1 h1(text) when 2 h2(text) when 3 h3(text) else Rainbow(text.to_s).bright.to_s end "#{body}\n\n" end |
#highlight(text) ⇒ Object
78 79 80 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 78 def highlight(text) md(text.to_s, :markdown_highlight) end |
#hrule ⇒ Object
120 121 122 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 120 def hrule "#{md(TABLE_DASH * @width.to_i.clamp(20, 80), :markdown_hrule)}\n\n" end |
#indent_block(text, prefix) ⇒ Object
154 155 156 157 158 159 160 161 162 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 154 def indent_block(text, prefix) text.to_s.lines.map { |line| if line.strip.empty? line else "#{prefix}#{line}" end }.join end |
#inline(text) ⇒ Object
235 236 237 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 235 def inline(text) text.to_s end |
#linebreak ⇒ Object
124 125 126 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 124 def linebreak "\n" end |
#link(link, _title, content) ⇒ Object
60 61 62 63 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 60 def link(link, _title, content) label = content.to_s.empty? ? link : content "#{md(label, :markdown_link)} #{md("<#{link}>", :markdown_url)}" end |
#list(contents, _type) ⇒ Object
132 133 134 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 132 def list(contents, _type) "#{contents}\n" end |
#list_item(text, _type) ⇒ Object
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 136 def list_item(text, _type) text = render_inline_html(CGI.unescapeHTML(text.to_s)) head, rest = text.to_s.strip.split(/\n+/, 2) out = wrap( head.to_s.strip, first_prefix: " • ", rest_prefix: " ", ) if rest && !rest.empty? out << "\n" out << indent_block(rest.rstrip, " ") end out << "\n" out end |
#normal_text(text) ⇒ Object
33 34 35 36 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 33 def normal_text(text) text = render_inline_html(CGI.unescapeHTML(text.to_s)) text end |
#pad_visible(text, width) ⇒ Object
229 230 231 232 233 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 229 def pad_visible(text, width) padding = width - Fatty::Ansi.visible_length(text) padding = 0 if padding.negative? "#{text}#{' ' * padding}" end |
#paragraph(text) ⇒ Object
128 129 130 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 128 def paragraph(text) "#{wrap(text)}\n\n" end |
#quote(text) ⇒ Object
86 87 88 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 86 def quote(text) "“#{text}”" end |
#raw_html(html) ⇒ Object
38 39 40 41 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 38 def raw_html(html) text = CGI.unescapeHTML(html.to_s) render_inline_html(text) end |
#render_inline_html(text) ⇒ Object
43 44 45 46 47 48 49 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 43 def render_inline_html(text) text.to_s .gsub(%r{<br\s*/?>}i, HARD_BREAK) .gsub(%r{<span\s+class=["']underline["']>(.*?)</span>}m) do md(Regexp.last_match(1), :markdown_underline) end end |
#render_table_row_cells(row, widths, header: false) ⇒ Object
211 212 213 214 215 216 217 218 219 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 211 def render_table_row_cells(row, widths, header: false) cells = widths.each_with_index.map do |width, index| text = row[index].to_s text = header ? th(text) : td(text) pad_visible(text, width) end " │ #{cells.join(' │ ')} │" end |
#render_table_separator(widths) ⇒ Object
221 222 223 224 225 226 227 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 221 def render_table_separator(widths) parts = widths.map do |width| TABLE_DASH * (width + 2) end " #{TABLE_BAR}#{parts.join(TABLE_BAR)}#{TABLE_BAR}" end |
#rouge_lexer(language, code) ⇒ Object
259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 259 def rouge_lexer(language, code) lexer = if !language.empty? Rouge::Lexer.find_fancy(language, code) else Rouge::Lexer.guess(source: code) end lexer || Rouge::Lexers::PlainText.new rescue StandardError Rouge::Lexers::PlainText.new end |
#strikethrough(text) ⇒ Object
Curses does not support strike-through, but this emulates it with unicode "combining characters" by adding a "Long Stroke Overlay" (U+0366) after each character, which overlays each with a strike-through overlay. We just had to make sure that Ansi.visible_length takes these into account in computing width.
56 57 58 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 56 def strikethrough(text) text.to_s.each_char.map { |ch| "#{ch}\u0336" }.join end |
#table(header, body) ⇒ Object
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 168 def table(header, body) rows = (header + body).lines.map do |line| line.chomp.split(CELL_SEP, -1) end widths = table_widths(rows) rendered = rows.each_with_index.map do |row, index| header_row = index.zero? line = render_table_row_cells(row, widths, header: header_row) if header_row [line, render_table_separator(widths)].join("\n") else line end end rendered.join("\n") + "\n\n" end |
#table_cell(content, _alignment) ⇒ Object
194 195 196 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 194 def table_cell(content, _alignment) inline(content.strip) + CELL_SEP end |
#table_row(content) ⇒ Object
190 191 192 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 190 def table_row(content) content.chomp.delete_suffix(CELL_SEP) + "\n" end |
#table_widths(rows) ⇒ Object
198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 198 def table_widths(rows) widths = [] rows.each do |row| row.each_with_index do |cell, index| width = Fatty::Ansi.visible_length(cell) widths[index] = [widths[index] || 0, width].max end end widths end |
#td(text) ⇒ Object
255 256 257 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 255 def td(text) md(text.to_s, :markdown_table_cell) end |
#th(text) ⇒ Object
251 252 253 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 251 def th(text) md(text.to_s, :markdown_table_header) end |