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, theme: nil, truecolor: false) ⇒ 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, theme: nil, truecolor: false) ⇒ AnsiRenderer
Returns a new instance of AnsiRenderer.
10 11 12 13 14 15 16 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 10 def initialize(width: 80, palette: nil, theme: nil, truecolor: false) super() @width = width.to_i @palette = palette || {} @theme = theme || {} @truecolor = truecolor end |
Instance Method Details
#autolink(link, _link_type) ⇒ Object
84 85 86 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 84 def autolink(link, _link_type) md(link.to_s, :markdown_link) end |
#block_code(code, language) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 18 def block_code(code, language) lexer = rouge_lexer(language.to_s, code.to_s) formatter = rouge_formatter 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
92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 92 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
67 68 69 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 67 def codespan(code) md(code.to_s, :markdown_code) end |
#double_emphasis(text) ⇒ Object
71 72 73 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 71 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.
76 77 78 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 76 def emphasis(text) md(text.to_s, :markdown_emphasis) end |
#h1(text) ⇒ Object
241 242 243 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 241 def h1(text) md(text.to_s, :markdown_h1) end |
#h2(text) ⇒ Object
245 246 247 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 245 def h2(text) md(text.to_s, :markdown_h2) end |
#h3(text) ⇒ Object
249 250 251 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 249 def h3(text) md(text.to_s, :markdown_h3) end |
#header(text, level) ⇒ Object
107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 107 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
80 81 82 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 80 def highlight(text) md(text.to_s, :markdown_highlight) end |
#hrule ⇒ Object
122 123 124 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 122 def hrule "#{md(TABLE_DASH * @width.to_i.clamp(20, 80), :markdown_hrule)}\n\n" end |
#indent_block(text, prefix) ⇒ Object
156 157 158 159 160 161 162 163 164 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 156 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
237 238 239 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 237 def inline(text) text.to_s end |
#linebreak ⇒ Object
126 127 128 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 126 def linebreak "\n" end |
#link(link, _title, content) ⇒ Object
62 63 64 65 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 62 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
134 135 136 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 134 def list(contents, _type) "#{contents}\n" end |
#list_item(text, _type) ⇒ Object
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 138 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
35 36 37 38 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 35 def normal_text(text) text = render_inline_html(CGI.unescapeHTML(text.to_s)) text end |
#pad_visible(text, width) ⇒ Object
231 232 233 234 235 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 231 def pad_visible(text, width) padding = width - Fatty::Ansi.visible_length(text) padding = 0 if padding.negative? "#{text}#{' ' * padding}" end |
#paragraph(text) ⇒ Object
130 131 132 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 130 def paragraph(text) "#{wrap(text)}\n\n" end |
#quote(text) ⇒ Object
88 89 90 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 88 def quote(text) "“#{text}”" end |
#raw_html(html) ⇒ Object
40 41 42 43 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 40 def raw_html(html) text = CGI.unescapeHTML(html.to_s) render_inline_html(text) end |
#render_inline_html(text) ⇒ Object
45 46 47 48 49 50 51 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 45 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
213 214 215 216 217 218 219 220 221 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 213 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
223 224 225 226 227 228 229 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 223 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
261 262 263 264 265 266 267 268 269 270 271 272 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 261 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.
58 59 60 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 58 def strikethrough(text) text.to_s.each_char.map { |ch| "#{ch}\u0336" }.join end |
#table(header, body) ⇒ Object
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 170 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
196 197 198 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 196 def table_cell(content, _alignment) inline(content.strip) + CELL_SEP end |
#table_row(content) ⇒ Object
192 193 194 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 192 def table_row(content) content.chomp.delete_suffix(CELL_SEP) + "\n" end |
#table_widths(rows) ⇒ Object
200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 200 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
257 258 259 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 257 def td(text) md(text.to_s, :markdown_table_cell) end |
#th(text) ⇒ Object
253 254 255 |
# File 'lib/fatty/markdown/ansi_renderer.rb', line 253 def th(text) md(text.to_s, :markdown_table_header) end |