Module: RubyRich::Markdown::TerminalConverter::MermaidRenderer

Defined in:
lib/ruby_rich/markdown.rb

Overview

—- Mermaid diagram renderer —- Renders pie charts inline; other diagram types show source with a hint to install ‘mmdc` for full rendering.

Constant Summary collapse

BAR_MAX =
32

Class Method Summary collapse

Class Method Details

.AnsiCodeObject



926
927
928
# File 'lib/ruby_rich/markdown.rb', line 926

def self.AnsiCode
  ::RubyRich::AnsiCode
end

.detect_type(source) ⇒ Object



850
851
852
853
854
855
856
857
858
859
# File 'lib/ruby_rich/markdown.rb', line 850

def self.detect_type(source)
  first = source.lines.first&.strip&.downcase || ""
  return :pie if first.start_with?("pie")
  return :flowchart if first.start_with?("flowchart") || first.start_with?("graph")
  return :sequence  if first.start_with?("sequencediagram")
  return :class     if first.start_with?("classdiagram")
  return :gantt     if first.start_with?("gantt")
  return :state     if first.start_with?("statediagram")
  :generic
end

.render(source, width = 80) ⇒ Object



837
838
839
840
841
842
843
844
845
846
847
848
# File 'lib/ruby_rich/markdown.rb', line 837

def self.render(source, width = 80)
  trimmed = source.strip
  return "" if trimmed.empty?

  type = detect_type(trimmed)
  case type
  when :pie
    render_pie(trimmed, width)
  else
    render_fallback(trimmed, type, width)
  end
end

.render_fallback(source, type, width) ⇒ Object

Fallback: show diagram source with a labelled header.



908
909
910
911
912
913
914
915
916
917
918
# File 'lib/ruby_rich/markdown.rb', line 908

def self.render_fallback(source, type, width)
  label = type.to_s.capitalize
  pad = (width - label.length - 2).clamp(2, 60)
  lines = source.lines.map(&:chomp)
  [
    "#{tc(:code_border)}┌─ #{label} #{'' * pad}#{AnsiCode.reset}",
    *lines.map { |l| "#{tc(:code_border)}#{AnsiCode.reset} #{l}" },
    "#{tc(:code_border)}#{'' * (width - 2)}#{AnsiCode.reset}",
    "#{tc(:muted || :heading_4_6)}Install mmdc (npm i -g @mermaid-js/mermaid-cli) for full diagram rendering.#{AnsiCode.reset}",
  ].join("\n")
end

.render_pie(source, width) ⇒ Object

Pie chart → horizontal bar chart with percentage labels.



862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
# File 'lib/ruby_rich/markdown.rb', line 862

def self.render_pie(source, width)
  title = ""
  entries = []
  source.each_line do |line|
    line = line.strip
    next if line.empty?
    if line.downcase.start_with?("pie")
      rest = line[3..].strip
      if rest.downcase.start_with?("title")
        title = rest[5..].strip
      end
      next
    end
    if line.downcase.start_with?("title")
      title = line[5..].strip
      next
    end
    # Parse "label" : value
    label_part, value_part = line.split(":", 2).map(&:strip)
    next unless label_part && value_part
    label = label_part.delete_prefix('"').delete_suffix('"')
    value = value_part.to_f
    entries << [label, value] if value > 0
  end

  return "[Mermaid pie: no data]" if entries.empty?

  total = entries.sum { |_l, v| v }
  return "[Mermaid pie: total is zero]" if total <= 0

  max_label = entries.map { |l, _| l.length }.max
  out = +""
  out << "#{tc(:heading_3)}#{title}#{AnsiCode.reset}\n" unless title.empty?

  entries.each do |label, value|
    pct = value / total * 100.0
    filled = (pct / 100.0 * BAR_MAX).round
    half = (pct / 100.0 * BAR_MAX * 2).round % 2 == 1
    bar = "" * filled + (half ? "" : "")
    out << sprintf("%-#{BAR_MAX + 1}s %-#{max_label}s %5.1f%%\n", bar, label, pct)
  end

  out.strip
end

.tc(key) ⇒ Object

Proxy theme colour access (same instance as TerminalConverter).



921
922
923
924
# File 'lib/ruby_rich/markdown.rb', line 921

def self.tc(key)
  color, bright = MarkdownTheme[key]
  AnsiCode.color(color, bright)
end