Class: Kramdown::ANSI
- Inherits:
-
Converter::Base
- Object
- Converter::Base
- Kramdown::ANSI
- Includes:
- Width
- Defined in:
- lib/kramdown/ansi.rb,
lib/kramdown/ansi.rb
Overview
A converter class that transforms Kramdown documents into ANSI-formatted terminal output.
The Kramdown::ANSI class extends Kramdown::Converter::Base to provide functionality for rendering Markdown documents with ANSI escape sequences for terminal display. It handles various Markdown elements such as headers, paragraphs, lists, and code blocks, applying configurable ANSI styles to enhance the visual presentation in terminals.
Defined Under Namespace
Modules: Pager, Width Classes: Styles
Constant Summary collapse
- BLOCKQUOTE_QUOTES =
[ %w[“ ”], %w[‘ ’], %w[ » « ], %w[ › ‹ ], ].map(&:freeze).freeze
Constants included from Width
Class Method Summary collapse
-
.parse(source, options = {}) ⇒ String
Parses the given markdown source into ANSI formatted terminal output.
Instance Method Summary collapse
-
#apply_style(name) {|String| ... } ⇒ String
private
The apply_style method applies ANSI styling to content by utilizing the configured styles and yielding the content to be styled.
-
#blockquote_quote(level) {|String| ... } ⇒ String
private
Wraps the content of a blockquote level with the corresponding typographic quotation marks, cycling through a predefined set of quote pairs based on the nesting depth.
-
#convert(el, opts = {}) ⇒ String
The convert method dispatches to type-specific conversion methods based on the element's type.
-
#convert_a(el, opts) ⇒ String
The convert_a method processes an anchor element by applying hyperlink formatting to its content.
-
#convert_blank(_el, opts) ⇒ String
The convert_blank method handles blank line conversion in Markdown documents.
-
#convert_blockquote(el, opts) ⇒ String
The convert_blockquote method processes a blockquote element by applying proper formatting.
-
#convert_br(_el, opts) ⇒ String
The convert_br method handles the conversion of line break elements.
-
#convert_codeblock(el, _opts) ⇒ String
The convert_codeblock method processes a code block element by applying ANSI styling to its content.
-
#convert_codespan(el, _opts) ⇒ String
The convert_codespan method processes a code span element by applying ANSI styling to its content.
-
#convert_em(el, opts) ⇒ String
The convert_em method processes an emphasis element by applying ANSI styling to its content.
-
#convert_entity(el, _opts) ⇒ String
The convert_entity method processes an entity element by extracting its character value.
-
#convert_header(el, opts) ⇒ String
The convert_header method processes a header element by applying ANSI styling and adding a newline.
-
#convert_hr(_el, _opts) ⇒ String
The convert_hr method processes a horizontal rule element by generating a full-width separator line.
-
#convert_html_element(el, opts) ⇒ String
The convert_html_element method processes HTML inline elements such as , , , and by applying the corresponding ANSI styles to their content.
-
#convert_img(el, _opts) ⇒ String
The convert_img method processes an image element by extracting its source URL and alternative text, formatting the display with a fallback to the URL if the alt text is empty, and applying hyperlink styling.
-
#convert_li(el, opts) ⇒ String
The convert_li method processes a list item element by applying indentation and handling newlines.
-
#convert_ol(el, opts) ⇒ String
The convert_ol method processes an ordered list element by applying numbered bullet point formatting and indentation.
-
#convert_p(el, opts) ⇒ String
The convert_p method processes a paragraph element by calculating the appropriate text width based on the terminal size and list indentation, then wraps the content accordingly.
-
#convert_root(el, opts) ⇒ String
The convert_root method processes the root element of a Kramdown document.
-
#convert_smart_quote(el, _opts) ⇒ String
The convert_smart_quote method processes smart quote entities by determining whether to output a double quotation mark or single quotation mark based on the entity's type.
-
#convert_strong(el, opts) ⇒ String
The convert_strong method processes a strong emphasis element by applying ANSI styling to its content.
-
#convert_table(el, opts) ⇒ String
The convert_table method processes a table element by creating a terminal table instance, applying styling and alignment options, and generating formatted output with newlines.
-
#convert_tbody(el, opts) ⇒ String
The convert_tbody method processes a table body element by collecting its inner content.
-
#convert_td(el, opts) ⇒ String
The convert_td method processes a table data cell element by delegating its content conversion to the inner method.
-
#convert_text(el, _opts) ⇒ String
The convert_text method processes a text element by extracting its value.
-
#convert_tfoot(el, opts) ⇒ String
The convert_tfoot method handles the conversion of table footer elements.
-
#convert_thead(el, opts) ⇒ String
The convert_thead method processes a table header element by extracting and formatting the heading rows from the table content, then assigns them to the terminal table instance.
-
#convert_tr(el, opts) ⇒ String
The convert_tr method processes a table row element by calculating column widths based on content size, wrapping text to fit within the terminal width, and adding the formatted row to the terminal table instance.
-
#convert_ul(el, opts) ⇒ String
The convert_ul method processes an unordered list element by applying bullet point formatting and indentation.
-
#convert_xml_comment ⇒ String
The convert_xml_comment method handles XML comment elements by returning an empty string.
-
#convert_xml_pi ⇒ String
The convert_xml_pi method handles the conversion of XML processing instruction elements.
-
#initialize(root, options) ⇒ void
constructor
Initializes a new Kramdown::ANSI converter instance with optional ANSI styling configuration.
-
#inner(el, opts) {|Kramdown::Element, Integer, String| ... } ⇒ String
The inner method processes child elements of a given element and applies optional block processing to each child.
-
#newline(text, count: 1) ⇒ String
The newline method appends a specified number of newline characters to the end of a given text string.
Methods included from Width
#display_width, display_width, #remove_ansi_escapes, remove_ansi_escapes, #truncate, truncate, #width, width, #wrap, wrap
Constructor Details
Class Method Details
.parse(source, options = {}) ⇒ String
Parses the given markdown source into ANSI formatted terminal output.
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/kramdown/ansi.rb', line 90 def self.parse(source, = {}) = { input: :mygfm, auto_ids: false, entity_output: :as_char }.merge( .transform_keys(&:to_sym) ) # Insert blank line before GFM pipe tables glued to preceding # content; kramdown requires it to parse the table correctly. # # Matches: a non-table line immediately followed by a table header, # a valid GFM separator row, and at least one body row. # A two-line "table" (header + separator, no body) is not a table # per GFM, so no blank line is inserted. source = source.gsub( / ( [^|\n][^\n]*\n ) # $1: preceding line (not a pipe line) ( \|[^\n]*\n ) # $2: table header (starts with |) ( \|(?:\s*:?-+:?\s*\|)+\n ) # $3: GFM separator + newline ( \|[^\n]* ) # $4: first body row (starts with |) \n /x, "\\1\n\\2\\3\\4\n" ) # Insert blank line after a table's last row when glued to # following content; kramdown requires it to close the table. # # A following line that contains a pipe is likely a table row # (separator or body), so we keep it glued. source = source.gsub( /(\|[^\n]*\n)([^|\n][^\n]*)/ ) do |match| row, next_line = $1, $2 next_line.include?('|') ? match : "#{row}\n#{next_line}" end @doc = Kramdown::Document.new(source, ).to_ansi end |
Instance Method Details
#apply_style(name) {|String| ... } ⇒ String (private)
The apply_style method applies ANSI styling to content by utilizing the configured styles and yielding the content to be styled.
661 662 663 |
# File 'lib/kramdown/ansi.rb', line 661 def apply_style(name, &block) @ansi_styles.apply(name, &block) end |
#blockquote_quote(level) {|String| ... } ⇒ String (private)
Wraps the content of a blockquote level with the corresponding typographic quotation marks, cycling through a predefined set of quote pairs based on the nesting depth.
300 301 302 303 |
# File 'lib/kramdown/ansi.rb', line 300 def blockquote_quote(level, &block) quote = BLOCKQUOTE_QUOTES[level % BLOCKQUOTE_QUOTES.size] quote[0] + block.() + quote[1] end |
#convert(el, opts = {}) ⇒ String
The convert method dispatches to type-specific conversion methods based on the element's type.
142 143 144 |
# File 'lib/kramdown/ansi.rb', line 142 def convert(el, opts = {}) send("convert_#{el.type}", el, opts) end |
#convert_a(el, opts) ⇒ String
The convert_a method processes an anchor element by applying hyperlink formatting to its content.
259 260 261 262 |
# File 'lib/kramdown/ansi.rb', line 259 def convert_a(el, opts) url = el.attr['href'] hyperlink(url) { inner(el, opts) } end |
#convert_blank(_el, opts) ⇒ String
The convert_blank method handles blank line conversion in Markdown documents.
This method determines whether a blank element should produce output based on the context of the surrounding content. It checks if the current result ends with double newlines or is empty, and returns an appropriate newline character to maintain proper spacing in the rendered output.
197 198 199 |
# File 'lib/kramdown/ansi.rb', line 197 def convert_blank(_el, opts) opts[:result] =~ /\n\n\Z|\A\Z/ ? "" : "\n" end |
#convert_blockquote(el, opts) ⇒ String
The convert_blockquote method processes a blockquote element by applying proper formatting.
This method takes a blockquote element and formats its content with quotation marks while ensuring appropriate newline handling. It delegates the inner content processing to the inner method and then wraps the result with quotation marks.
proper newlines
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
# File 'lib/kramdown/ansi.rb', line 318 def convert_blockquote(el, opts) old_level = opts[:blockquote_level] ||= -1 level = opts[:blockquote_level] = old_level + 1 if level.zero? newline( blockquote_quote(level) { apply_style(:blockquote) { inner(el, opts).strip } }.gsub(/^/, ' ') ) else blockquote_quote(level) { inner(el, opts).strip }.gsub(/^/, ' ') end ensure opts[:blockquote_level] = old_level end |
#convert_br(_el, opts) ⇒ String
The convert_br method handles the conversion of line break elements.
This method processes HTML line break elements (br tags) by returning an empty string, effectively ignoring them during the ANSI terminal output conversion process. It is part of the Kramdown::ANSI converter's element handling suite.
during conversion
627 628 629 |
# File 'lib/kramdown/ansi.rb', line 627 def convert_br(_el, opts) '' end |
#convert_codeblock(el, _opts) ⇒ String
The convert_codeblock method processes a code block element by applying ANSI styling to its content.
280 281 282 |
# File 'lib/kramdown/ansi.rb', line 280 def convert_codeblock(el, _opts) apply_style(:code) { el.value } end |
#convert_codespan(el, _opts) ⇒ String
The convert_codespan method processes a code span element by applying ANSI styling to its content.
270 271 272 |
# File 'lib/kramdown/ansi.rb', line 270 def convert_codespan(el, _opts) apply_style(:code) { el.value } end |
#convert_em(el, opts) ⇒ String
The convert_em method processes an emphasis element by applying ANSI styling to its content.
249 250 251 |
# File 'lib/kramdown/ansi.rb', line 249 def convert_em(el, opts) apply_style(:em) { inner(el, opts) } end |
#convert_entity(el, _opts) ⇒ String
The convert_entity method processes an entity element by extracting its character value.
582 583 584 |
# File 'lib/kramdown/ansi.rb', line 582 def convert_entity(el, _opts) el.value.char end |
#convert_header(el, opts) ⇒ String
The convert_header method processes a header element by applying ANSI styling and adding a newline.
216 217 218 |
# File 'lib/kramdown/ansi.rb', line 216 def convert_header(el, opts) newline apply_style(:header) { inner(el, opts) } end |
#convert_hr(_el, _opts) ⇒ String
The convert_hr method processes a horizontal rule element by generating a full-width separator line.
This method creates a horizontal rule (divider) using the Unicode line-drawing character and applies proper newline formatting to ensure correct spacing in the terminal output.
terminal width with newlines
345 346 347 |
# File 'lib/kramdown/ansi.rb', line 345 def convert_hr(_el, _opts) newline ?─ * width(percentage: 100) end |
#convert_html_element(el, opts) ⇒ String
The convert_html_element method processes HTML inline elements such as , , , and by applying the corresponding ANSI styles to their content. It handles emphasis and strong formatting tags specifically, while ignoring other HTML elements by returning an empty string.
empty string for other elements
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
# File 'lib/kramdown/ansi.rb', line 433 def convert_html_element(el, opts) if el.value == 'i' || el.value == 'em' apply_style(:em) { inner(el, opts) } elsif el.value == 'b' || el.value == 'strong' apply_style(:strong) { inner(el, opts) } elsif el.value == 'ins' || el.value == 'u' apply_style(:ins) { inner(el, opts) } elsif el.value == 'mark' apply_style(:mark) { inner(el, opts) } elsif el.value == 'del' || el.value == 's' apply_style(:del) { inner(el, opts) } elsif el.value == 'tt' apply_style(:code) { inner(el, opts) } elsif el.value == 'small' apply_style(:small) { inner(el, opts) } elsif %w[ span sub sup ].include?(el.value) inner(el, opts) else '' end end |
#convert_img(el, _opts) ⇒ String
The convert_img method processes an image element by extracting its source URL and alternative text, formatting the display with a fallback to the URL if the alt text is empty, and applying hyperlink styling.
356 357 358 359 360 361 362 |
# File 'lib/kramdown/ansi.rb', line 356 def convert_img(el, _opts) url = el.attr['src'] alt = el.attr['alt'] alt.strip.size == 0 and alt = url alt = '🖼 ' + alt hyperlink(url) { alt } end |
#convert_li(el, opts) ⇒ String
The convert_li method processes a list item element by applying indentation and handling newlines.
This method takes a list item element and modifies the conversion options to include appropriate indentation for nested lists. It then delegates the inner content processing to the inner method and ensures proper newline handling at the end of the content.
and newlines
418 419 420 421 422 |
# File 'lib/kramdown/ansi.rb', line 418 def convert_li(el, opts) opts = opts.dup opts[:list_indent] = 2 + opts[:list_indent].to_i newline inner(el, opts).sub(/\n+\Z/, '') end |
#convert_ol(el, opts) ⇒ String
The convert_ol method processes an ordered list element by applying numbered bullet point formatting and indentation.
This method takes an ordered list element and formats its child elements with sequential numbers, applying appropriate newline handling based on the list item's position, and adding indentation to align the content properly within the terminal output.
and proper indentation
397 398 399 400 401 402 403 404 |
# File 'lib/kramdown/ansi.rb', line 397 def convert_ol(el, opts) list_indent = opts[:list_indent].to_i inner(el, opts) { |_inner_el, index, content| result = '%u. %s' % [ index + 1, content ] result = newline(result, count: index <= el.children.size - 1 ? 1 : 2) result.gsub(/^/, ' ' * list_indent) } end |
#convert_p(el, opts) ⇒ String
The convert_p method processes a paragraph element by calculating the appropriate text width based on the terminal size and list indentation, then wraps the content accordingly.
227 228 229 230 231 |
# File 'lib/kramdown/ansi.rb', line 227 def convert_p(el, opts) length = width(percentage: 90) - opts[:list_indent].to_i length < 0 and return '' newline wrap(inner(el, opts), length:) end |
#convert_root(el, opts) ⇒ String
The convert_root method processes the root element of a Kramdown document.
This method serves as the entry point for converting the top-level element of a Markdown document into its ANSI-formatted terminal representation. It delegates the actual processing to the inner method, which handles the recursive conversion of child elements.
182 183 184 |
# File 'lib/kramdown/ansi.rb', line 182 def convert_root(el, opts) inner(el, opts) end |
#convert_smart_quote(el, _opts) ⇒ String
The convert_smart_quote method processes smart quote entities by determining whether to output a double quotation mark or single quotation mark based on the entity's type.
double quotes, and a single quotation mark for other smart quote entities
639 640 641 |
# File 'lib/kramdown/ansi.rb', line 639 def convert_smart_quote(el, _opts) el.value.to_s =~ /[rl]dquo/ ? "\"" : "'" end |
#convert_strong(el, opts) ⇒ String
The convert_strong method processes a strong emphasis element by applying ANSI styling to its content.
239 240 241 |
# File 'lib/kramdown/ansi.rb', line 239 def convert_strong(el, opts) apply_style(:strong) { inner(el, opts) } end |
#convert_table(el, opts) ⇒ String
The convert_table method processes a table element by creating a terminal table instance, applying styling and alignment options, and generating formatted output with newlines.
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 |
# File 'lib/kramdown/ansi.rb', line 462 def convert_table(el, opts) # Kramdown's base parser is more permissive than GFM: it accepts # any pipe-delimited line as a table row, even without a header. # GFM mandates a header + separator row minimum, so a :table # element without :thead is just pipe-separated prose. unless el.children.any? { |c| c.type == :thead } rows = el.children.select { |c| c.type == :tbody }.flat_map do |tbody| tbody.children.map do |row| row.children.map { |cell| convert(cell, opts).strip }.join(' | ') end end return newline rows.join("\n") end table = Terminal::Table.new table.style = { all_separators: true, border: :unicode_round, } opts[:table] = table inner(el, opts) el.[:alignment].each_with_index do |a, i| a == :default and next opts[:table].align_column(i, a) end newline table.to_s end |
#convert_tbody(el, opts) ⇒ String
The convert_tbody method processes a table body element by collecting its inner content.
This method handles the conversion of HTML table body elements, gathering all child elements' content and returning it as a string. It serves as part of the table conversion process, working in conjunction with other table-related methods to generate properly formatted terminal output.
table body
516 517 518 519 |
# File 'lib/kramdown/ansi.rb', line 516 def convert_tbody(el, opts) res = +'' res << inner(el, opts) end |
#convert_td(el, opts) ⇒ String
The convert_td method processes a table data cell element by delegating its content conversion to the inner method.
572 573 574 |
# File 'lib/kramdown/ansi.rb', line 572 def convert_td(el, opts) inner(el, opts) end |
#convert_text(el, _opts) ⇒ String
The convert_text method processes a text element by extracting its value.
206 207 208 |
# File 'lib/kramdown/ansi.rb', line 206 def convert_text(el, _opts) el.value end |
#convert_tfoot(el, opts) ⇒ String
The convert_tfoot method handles the conversion of table footer elements.
This method processes table footer elements by returning an empty string, effectively ignoring footer content during the ANSI terminal output conversion. It is part of the table conversion process, working alongside other table-related methods to generate properly formatted terminal output.
footer element
532 533 534 |
# File 'lib/kramdown/ansi.rb', line 532 def convert_tfoot(el, opts) '' end |
#convert_thead(el, opts) ⇒ String
The convert_thead method processes a table header element by extracting and formatting the heading rows from the table content, then assigns them to the terminal table instance.
assignment of headings to the table instance
497 498 499 500 501 502 |
# File 'lib/kramdown/ansi.rb', line 497 def convert_thead(el, opts) rows = inner(el, opts) rows = rows.split(/\s*\|\s*/)[1..].map(&:strip) opts[:table].headings = rows '' end |
#convert_tr(el, opts) ⇒ String
The convert_tr method processes a table row element by calculating column widths based on content size, wrapping text to fit within the terminal width, and adding the formatted row to the terminal table instance.
addition of the row to the table instance
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 |
# File 'lib/kramdown/ansi.rb', line 544 def convert_tr(el, opts) return '' if el.children.empty? cols = el.children.map do |c| stripped = convert(c, opts).strip stripped.empty? ? ' ' : stripped end return '' if cols.empty? col_widths = cols.map { |c| display_width(c) } col_widths_sum = col_widths.sum full_width = width(percentage: 90) ratios = cols.each_with_index.map do |c, i| if col_widths_sum.zero? 1.0 / cols.size else col_widths[i] / col_widths_sum.to_f end end wrapped_cols = cols.zip(ratios).map { |c, r| wrap(c, length: r * full_width) } opts[:table] << wrapped_cols '' end |
#convert_ul(el, opts) ⇒ String
The convert_ul method processes an unordered list element by applying bullet point formatting and indentation.
This method takes an unordered list element and formats its child elements with bullet points, applying appropriate newline handling based on the list item's position, and adding indentation to align the content properly within the terminal output.
and proper indentation
376 377 378 379 380 381 382 383 |
# File 'lib/kramdown/ansi.rb', line 376 def convert_ul(el, opts) list_indent = opts[:list_indent].to_i inner(el, opts) { |_inner_el, index, content| result = '· %s' % content result = newline(result, count: index <= el.children.size - 1 ? 1 : 2) result.gsub(/^/, ' ' * list_indent) } end |
#convert_xml_comment ⇒ String
The convert_xml_comment method handles XML comment elements by returning an empty string.
This method is part of the Kramdown::ANSI converter and is responsible for processing XML comment elements that appear in the Markdown document. It ignores XML comments during the ANSI terminal output conversion process, returning an empty string to indicate that no content should be rendered for these elements.
during conversion
597 598 599 |
# File 'lib/kramdown/ansi.rb', line 597 def convert_xml_comment(*) '' end |
#convert_xml_pi ⇒ String
The convert_xml_pi method handles the conversion of XML processing instruction elements.
This method is part of the Kramdown::ANSI converter and is responsible for processing XML processing instruction elements that appear in the Markdown document. It ignores these elements during the ANSI terminal output conversion process, returning an empty string to indicate that no content should be rendered for these elements.
instructions are ignored during conversion
612 613 614 |
# File 'lib/kramdown/ansi.rb', line 612 def convert_xml_pi(*) '' end |
#inner(el, opts) {|Kramdown::Element, Integer, String| ... } ⇒ String
The inner method processes child elements of a given element and applies optional block processing to each child.
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/kramdown/ansi.rb', line 156 def inner(el, opts, &block) result = +'' = opts.dup.merge(parent: el) el.children.each_with_index do |inner_el, index| [:index] = index [:result] = result begin content = send("convert_#{inner_el.type}", inner_el, ) result << (block&.(inner_el, index, content) || content) rescue NameError => e warning "Caught #{e.class} for #{inner_el.type}" end end result end |
#newline(text, count: 1) ⇒ String
The newline method appends a specified number of newline characters to the end of a given text string.
649 650 651 |
# File 'lib/kramdown/ansi.rb', line 649 def newline(text, count: 1) text.gsub(/\n*\z/, ?\n * count) end |