limner 0.1.0

A ratatui markdown renderer with image placeholders, code blocks, and styled headings
Documentation

limner

A ratatui markdown renderer with image placeholders, styled headings, code blocks, and more.

[dependencies]
limner = "0.1"

Usage

use limner::{render_markdown, MarkdownStyle};
use ratatui::widgets::{Paragraph, Wrap};

let content = "# Hello\n\nThis is **markdown** with `code`.";

let style = MarkdownStyle {
    heading_1: ratatui::style::Style::new().green().bold(),
    ..MarkdownStyle::default()
};

let lines = render_markdown(content, &style, 80);
let paragraph = Paragraph::new(lines).wrap(Wrap { trim: false });

Output lines work directly with ratatui's Paragraph widget — scrolling, line counting, and word-wrapping are all handled by the existing widget.

Features

  • Headings (levels 1–3) with configurable styles
  • Bold, italic, strikethrough with proper nesting
  • Inline code and code blocks with full-width background
  • Links with styled text and prefix
  • Images rendered as placeholder text (🖼 alt-text)
  • Blockquotes with per-line indicators
  • Ordered and unordered lists
  • Horizontal rules
  • Lightweight — only depends on ratatui, pulldown-cmark, and unicode-width
  • Terminal image rendering (optional) — via image-protocol feature; requires a terminal that supports Kitty graphics protocol, Sixel, or iTerm2

Terminal image rendering

Enable the image-protocol feature to render images via the terminal's native graphics protocol (Kitty, Sixel, or iTerm2):

[dependencies]
limner = { version = "0.1", features = ["image-protocol"] }

Images in markdown (![alt](url)) are tracked as ImageInfo metadata. After drawing the ratatui frame, call prepare_inline_images() to insert Image widgets at the correct positions:

use limner::{render_markdown, render_image};
use std::collections::HashMap;

let result = render_markdown(&content, &style, width);
let mut protocol_cache = HashMap::new();
let picker = render_image::Picker::from_query_stdio()?;
let font_size = picker.font_size();
let placements = render_image::prepare_inline_images(
    &mut result.lines,
    &result.images,
    &image_cache,
    &mut protocol_cache,
    &picker,
    &font_size,
    content_width,
    6,
);

// Then render Image widgets inside terminal.draw() using the placements.

The caller is responsible for populating the image_cache (HashMap<String, DynamicImage>).

Demo

# Text-only (no image rendering required)
cargo run --example demo

# With terminal image rendering (Kitty/Sixel/iTerm2)
cargo run --example demo --features image-protocol

Theming

MarkdownStyle exposes every element's [Style] and text prefix. Set only the fields you want to override:

let my_style = MarkdownStyle {
    heading_1: Style::new().fg(Color::Rgb(255, 200, 100)).bold(),
    code_block: Style::new().fg(Color::Rgb(200, 200, 100)),
    code_block_bg: Color::Rgb(30, 30, 30),
    link: Style::new().cyan().underlined(),
    ..MarkdownStyle::default()
};

License

MIT