Class: RubyRich::Markdown

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_rich/markdown.rb

Defined Under Namespace

Modules: Frontmatter Classes: TerminalConverter

Constant Summary collapse

MarkdownTheme =

Markdown rendering colour theme. ===

Each key maps to ‘[color, bright]` accepted by AnsiCode.

{
  heading_1:         [:cyan,     true],
  heading_2:         [:blue,     true],
  heading_3:         [:yellow,   true],
  heading_4_6:       [:black,    true],
  heading_underline: [:cyan,     true],  # H1
  heading_underline2:[:blue,     true],  # H2
  text:              [:white,    true],
  strong_text:       [:white,    true],
  code_border:       [:black,    true],
  code_bg:           [:black,    true],
  code_fg:           [:white,    true],
  inline_code_fg:    [:black,    false],
  inline_code_bg:    [:white,    false],
  blockquote_marker: [:black,    true],
  blockquote_text:   [:white,    true],
  blockquote_italic: true,
  list_level_1:      [:cyan,     true],
  list_level_2:      [:magenta,  true],
  list_level_3:      [:yellow,   true],
  ordered_list:      [:cyan,     true],
  task_checked:      [:green,    true],
  task_unchecked:    [:black,    true],
  link_text:         [:blue,     true],
  link_url:          [:black,    true],
  image_label:       [:magenta,  true],
  rule:              [:black,    true],
  footnote:          [:magenta,  true],
  abbreviation:      [:black,    true],
  math:              [:magenta,  true],
  mark_fg:           [:black,    false],
  mark_bg:           [:yellow,   false],
  kbd_fg:            [:black,    false],
  kbd_bg:            [:white,    false],
  table_border:      :simple
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Markdown

Returns a new instance of Markdown.



1088
1089
1090
# File 'lib/ruby_rich/markdown.rb', line 1088

def initialize(options = {})
  @options = options
end

Class Method Details

.render(markdown_text, options = {}) ⇒ String

渲染 Markdown 文本为 ANSI 终端输出

Parameters:

  • markdown_text (String)

    输入的 Markdown 文本

  • options (Hash) (defaults to: {})

    渲染选项

Options Hash (options):

  • :width (Integer)

    终端宽度(默认 80)

  • :indent (String)

    缩进字符串(默认 ‘ ’)

  • :table_border_style (Symbol)

    表格边框样式 (:none, :simple, :full)

  • :kramdown (Hash)

    传递给 Kramdown::Document 的额外选项

Returns:

  • (String)

    ANSI 格式的终端输出



1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
# File 'lib/ruby_rich/markdown.rb', line 1026

def self.render(markdown_text, options = {})
  converter_options = {
    width: options[:width] || 80,
    indent: options[:indent] || '  ',
    table_border_style: options[:table_border_style] || :simple
  }

  # Pre-process frontmatter
  content, fm_pairs, fm_vertical = Frontmatter.extract(markdown_text)

  # Pre-process inline math $...$ (kramdown needs a math-engine gem for this)
  math_color = AnsiCode.color(*MarkdownTheme[:math])
  content = content.gsub(/(?<!\$)\$(?!\$)(.+?)(?<!\$)\$(?!\$)/) do
    rendered = TerminalConverter::LatexConverter.convert(Regexp.last_match(1).strip)
    "#{math_color}#{rendered}#{AnsiCode.reset}"
  end

  fm_output = ""
  if fm_pairs && !fm_pairs.empty?
    if fm_vertical
      # Vertical frontmatter: one column per key-value pair
      fm_output = render_frontmatter_vertical(fm_pairs, converter_options)
    else
      fm_output = render_frontmatter_horizontal(fm_pairs, converter_options)
    end
  end

  kramdown_opts = {
    input: 'GFM',                 # GitHub Flavored Markdown
    syntax_highlighter: nil,      # 自行处理语法高亮
    hard_wrap: false,
    html_to_native: true,
    line_width: converter_options[:width]
  }.merge(options[:kramdown] || {})

  doc = Kramdown::Document.new(content, kramdown_opts)
  result, _warnings = TerminalConverter.convert(doc.root, converter_options)
  "#{fm_output}#{result}"
end

.render_frontmatter_horizontal(pairs, opts) ⇒ Object

Render frontmatter as a horizontal 2-row table (few pairs).



1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
# File 'lib/ruby_rich/markdown.rb', line 1077

def self.render_frontmatter_horizontal(pairs, opts)
  keys = pairs.map(&:first)
  vals = pairs.map(&:last)
  tbl = RubyRich::Table.new(
    headers: keys,
    border_style: opts[:table_border_style] || :simple
  )
  tbl.add_row(vals)
  "#{tbl.render}\n\n"
end

.render_frontmatter_vertical(pairs, opts) ⇒ Object

Render frontmatter as a vertical key-value table (many pairs).



1067
1068
1069
1070
1071
1072
1073
1074
# File 'lib/ruby_rich/markdown.rb', line 1067

def self.render_frontmatter_vertical(pairs, opts)
  tbl = RubyRich::Table.new(
    headers: %w[Key Value],
    border_style: opts[:table_border_style] || :simple
  )
  pairs.each { |k, v| tbl.add_row([k, v]) }
  "#{tbl.render}\n\n"
end

Instance Method Details

#render(markdown_text) ⇒ Object



1092
1093
1094
# File 'lib/ruby_rich/markdown.rb', line 1092

def render(markdown_text)
  self.class.render(markdown_text, @options)
end