Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

rich_md

Rich Markdown: markdown rendered in ImGui: text styles, headings, lists, tables, images, links, code blocks, LaTeX math and diagrams.

render(markdown_string) draws a markdown text; render_unindented() accepts an indented one; render_file() renders a file. Run the app with immapp.run(..., with_markdown=True), which loads the fonts.

Its former name, imgui_bundle.imgui_md, stays as an alias.

The module imgui_bundle.rich_md, the Python API of Rich Markdown, from bindings/imgui_bundle/rich_md.pyi: 38 functions, 11 classes, 2 enums. Each entry gives the Python signature, then the C++ one, then the doc of the C++ header. The sections are the header’s.

render_this_file

def render_this_file(target: str = '') -> None

Renders ![[this_file#target]] (see resolve_transclusions): a program can be its own narrative. target: a section (“Intro”), its code (“Escape#code”), a code region, or empty (the whole file). (Python only; C++: RICHMD_RENDER_THIS_FILE)

document

def document(id: str, size: Optional[ImVec2Like] = None, options: Optional[DocumentOptions] = None) -> ContextManager[None]

A document, as a context manager: with rich_md.document("doc"): calls begin_document() on entry and end_document() on exit. (Python only; C++: BeginDocument() / EndDocument())

rich_md_host.h

MarkdownDownloadStatus (enum)

enum class MarkdownDownloadStatus

Status of a download (see HostServices::Download)

MemberValueC++
not_started0NotStartedDownload has not been initiated
downloading1DownloadingDownload is in progress (show placeholder)
ready2ReadyDownload complete, data is available
failed3FailedDownload failed, errorMessage has details

MarkdownDownloadResult (class)

struct MarkdownDownloadResult

Result of a download attempt

AttributeC++
status: MarkdownDownloadStatusMarkdownDownloadStatus status = MarkdownDownloadStatus::NotStarted;
error_message: strstd::string errorMessage;Only valid if status == Failed
MarkdownDownloadResult.__init__
def __init__(self) -> None

Autogenerated default constructor

MarkdownDownloadResult.fill_from_bytes
def fill_from_bytes(self, data: bytes) -> None

Fill the result data from a Python bytes object.

Python additions

Context (class)

A markdown context (its options, its fonts, its caches): made by create_context, destroyed by destroy_context. Opaque.

set_download_function

def set_download_function(fn: Optional[Callable[[str], MarkdownDownloadResult]]) -> None

Sets the function that downloads URL images (HostServices.Download), for every markdown context. imgui_bundle installs one at import (urllib in a thread on desktop, JS fetch in Pyodide).
Called every frame for a URL until it returns Ready or Failed; an asynchronous download returns
Downloading first and tracks its pending downloads itself. None disables URL images.

narrative_programming.h

resolve_transclusions

def resolve_transclusions(markdown: str, read_file: ReadTextFile, current_file: str = '', root: str = '') -> str
std::string ResolveTransclusions(const std::string& markdown, const ReadTextFile& readFile, const std::string& currentFile = "", const std::string& root = "");

ResolveTransclusions replaces the embeds of a markdown text: readFile reads a file (or returns std::nullopt); currentFile is the file the text comes from, if any. Render() calls it with the host’s ReadAsset.
The embeds name files beside or below the document only (root empty: the folder of currentFile; for a text from no file, relative paths, below the assets): a document from anyone must not show a file of the machine.
A caller that trusts the text widens it: root is the folder the embeds may reach, “/” for any file.

rich_md.h

render

def render(markdown_string: str) -> None
void Render(const std::string& markdownString);

Renders a markdown string. Its common indentation is removed first (so that a string written inside an indented function renders as expected; no-op on flush-left text), then its transclusions are resolved (see ResolveTransclusions; the files are read through the host’s ReadAsset).
Its size follows a size pushed with ImGui::PushFont(None, size), relative to the frame’s base size:
PushFont(None, ImGui::GetStyle().FontSizeBase * 0.8) renders it at 80%.

render_raw

def render_raw(markdown_string: str) -> None
void RenderRaw(const std::string& markdownString);

Renders a markdown string as is (no unindent, no transclusion)

push_selectable_text

def push_selectable_text(selectable: bool) -> None
void PushSelectableText(bool selectable);

Whether the text of the renders that follow can be selected, until the matching PopSelectableText(), in the same frame. For markdown inside something that reacts to a drag itself (a node of a node editor, a custom widget).

pop_selectable_text

def pop_selectable_text() -> None
void PopSelectableText();

set_selectable_text_default

def set_selectable_text_default(selectable: bool) -> None
void SetSelectableTextDefault(bool selectable);

Whether the text can be selected, outside of a PushSelectableText(): changes the option selectableText of the current context

Headings

Heading (class)

struct Heading

A heading of the last render

AttributeC++
level: intint level = 1;1 to 6
text: strstd::string text;without markup
slug: strstd::string slug;its anchor, made from the text as GitHub does (a repeated title gets -1, -2...)
y: floatfloat y = 0.f;its top, in its window’s content coordinates: SetScrollY(y) shows it at the top
hidden: boolbool hidden = false;inside a collapsed <details> or a fold: y is the one of what hides it
Heading.__init__
def __init__(self) -> None

Autogenerated default constructor

last_render_headings

def last_render_headings() -> List[Heading]
const std::vector<Heading>& LastRenderHeadings();

The headings of the last Render() call (valid until the next one)

fold_all_headings

def fold_all_headings(folded: bool) -> None
void FoldAllHeadings(bool folded);

Folds (or unfolds) all the foldable headings (MarkdownOptions::foldableHeadings), from the next frame: those of the current document between BeginDocument() and EndDocument(), else those of the last Render()

Documents

ScrollAnimation (enum)

enum class ScrollAnimation

The scroll to a match, a heading or an anchor: eased over scrollAnimationSeconds, unless reduced motion is asked

MemberValueC++
follow_system0FollowSystemanimated, unless the system asks for reduced motion (HostServices::PrefersReducedMotion)
always1Always
never2Never

DocumentOptions (class)

struct DocumentOptions

The options of a document

AttributeC++
toc: boolbool toc = true;
toc_min_headings: intint tocMinHeadings = 3;with fewer headings, no table of contents
toc_max_level: intint tocMaxLevel = 3;the deepest level listed
narrow_width: floatfloat narrowWidth = 40.f;
search: boolbool search = true;
scroll_animation: ScrollAnimationScrollAnimation scrollAnimation = ScrollAnimation::FollowSystem;
scroll_animation_seconds: floatfloat scrollAnimationSeconds = 0.3f;the duration of an animated scroll, whatever its distance
scroll_anchoring: boolbool scrollAnchoring = true;
foldable_headings: boolbool foldableHeadings = false;
DocumentOptions.__init__
def __init__(self) -> None

Autogenerated default constructor

begin_document

def begin_document(id: str, size: Optional[ImVec2Like] = None, options: Optional[DocumentOptions] = None) -> None
void BeginDocument(const char* id, ImVec2 size = ImVec2(0.f, 0.f), const DocumentOptions& options = DocumentOptions());

A document: the renders and the widgets drawn until EndDocument() share a scroll area and their headings. size: as BeginChild (0: all the available space). Call EndDocument() in the same frame. The content is always drawn: there is no return value to skip it. One document at a time.

Python bindings defaults:
If any of the params below is None, then its default value below will be used: * size: ImVec2(0., 0.) * options: DocumentOptions()

end_document

def end_document() -> None
void EndDocument();

render_document

def render_document(id: str, markdown: str, size: Optional[ImVec2Like] = None, options: Optional[DocumentOptions] = None) -> None
void RenderDocument(const char* id, const std::string& markdown, ImVec2 size = ImVec2(0.f, 0.f), const DocumentOptions& options = DocumentOptions());

The one-call form: BeginDocument(id, size, options), Render(markdown), EndDocument()

Python bindings defaults:
If any of the params below is None, then its default value below will be used: * size: ImVec2(0., 0.) * options: DocumentOptions()

document_heading

def document_heading(level: int, text: str, draw_title: bool = True) -> bool
bool DocumentHeading(int level, const std::string& text, bool drawTitle = true);

Starts a section of the document that is not markdown (widgets, a plot): a heading of the document, with its slug (an anchor for [text](#slug) links). drawTitle: draws the text as a markdown heading of that level; False when the title is drawn by other means (an ImGui text, a plot’s own title), or not at all. Returns whether the section shows: False when a fold hides it (MarkdownOptions::foldableHeadings), and the application skips its widgets.

Folding text

FoldingTextOptions (class)

struct FoldingTextOptions

The options of a folding text

AttributeC++
start_folded: boolbool startFolded = false;folded at first (else open, until the user folds it)
fold_on_click_elsewhere: boolbool foldOnClickElsewhere = false;it folds when the user clicks or taps elsewhere in the window
animation_seconds: floatfloat animationSeconds = 0.25f;the slide (none when the system asks for reduced motion)
FoldingTextOptions.__init__
def __init__(self) -> None

Autogenerated default constructor

render_folding

def render_folding(id: str, markdown: str, options: Optional[FoldingTextOptions] = None) -> bool
bool RenderFolding(const char* id, const std::string& markdown, const FoldingTextOptions& options = FoldingTextOptions());

Renders a markdown text, folded to its first paragraph (the headings before it stay) or to a line , or open; a link at its end folds or unfolds it. id: keeps its state, in the current window. Returns whether it is open.

Python bindings defaults:
If options is None, then its default value will be: FoldingTextOptions()

Options and callbacks

MarkdownFontOptions (class)

struct MarkdownFontOptions
AttributeC++
font_base_path: strstd::string fontBasePath = "fonts/Roboto/Roboto";
regular_size: floatfloat regularSize = 16.f;
header_size_factors: np.ndarrayfloat headerSizeFactors[6] = { 1.42f, 1.33f, 1.24f, 1.15f, 1.10f, 1.05f };ndarray[type=float, size=6] default:float( 1.42, 1.33, 1.24, 1.15, 1.10, 1.05 )
merge_fonts: List[str]std::vector<std::string> mergeFonts;
MarkdownFontOptions.__init__
def __init__(self) -> None

Autogenerated default constructor

MarkdownImage (class)

struct MarkdownImage
AttributeC++
texture_id: ImTextureIDImTextureID texture_id;
size: ImVec2ImVec2 size;
uv0: ImVec2ImVec2 uv0;
uv1: ImVec2ImVec2 uv1;
col_tint: ImVec4ImVec4 col_tint;
col_border: ImVec4ImVec4 col_border;
MarkdownImage.__init__
def __init__(self) -> None

Autogenerated default constructor

on_image_default

def on_image_default(image_path: str) -> Optional[MarkdownImage]
std::optional<MarkdownImage> OnImage_Default(const std::string& image_path);
def on_open_link_default(url: str) -> None
void OnOpenLink_Default(const std::string& url);

is_web_url

def is_web_url(url: str) -> bool
bool IsWebUrl(const std::string& url);

Whether a link is a web address (http:// or https://, any case): the only ones OnOpenLink_Default opens

MarkdownCallbacks (class)

struct MarkdownCallbacks
AttributeC++
on_open_link: StringFunctionStringFunction OnOpenLink = OnOpenLink_Default;
on_image: MarkdownImageFunctionMarkdownImageFunction OnImage = OnImage_Default;
on_html_div: HtmlDivFunctionHtmlDivFunction OnHtmlDiv;
on_html_span: HtmlSpanFunctionHtmlSpanFunction OnHtmlSpan;
can_use_child_windows: Callable[[], bool]std::function<bool()> CanUseChildWindows;
on_wiki_link: Callable[[str], None]std::function<void(const std::string& target)> OnWikiLink;
on_heading: Callable[[int, str], None]std::function<void(int level, const std::string& text)> OnHeading;
MarkdownCallbacks.__init__
def __init__(self) -> None

Autogenerated default constructor

MarkdownCallbacks.on_download_data
@property
def on_download_data(self) -> Optional[str]

@on_download_data.setter
def on_download_data(self, fn: Optional[Callable[[str], MarkdownDownloadResult]]) -> None

Deprecated: use rich_md.set_download_function. Returns None if not set, or a status string (reading back the callable itself is not supported).

MarkdownOptions (class)

struct MarkdownOptions
AttributeC++
font_options: MarkdownFontOptionsMarkdownFontOptions fontOptions;
callbacks: MarkdownCallbacksMarkdownCallbacks callbacks;
with_latex: boolbool withLatex = false;
autolinks: boolbool autolinks = true;
hard_soft_breaks: boolbool hardSoftBreaks = false;
selectable_text: boolbool selectableText = true;
foldable_headings: boolbool foldableHeadings = false;
foldable_headings_min_level: intint foldableHeadingsMinLevel = 2;the first level that folds (a “#” heading often titles the whole text)
MarkdownOptions.__init__
def __init__(self) -> None

Autogenerated default constructor

Context

create_context

def create_context(options: Optional[MarkdownOptions] = None) -> Context
Context* CreateContext(const MarkdownOptions& options = MarkdownOptions());

A context holds the options, the fonts and the caches (textures, formulas, diagrams). Most applications have one.

Contexts: CreateContext makes one, any time after ImGui::CreateContext(); it becomes the current context when there is none. The fonts load at the first Render() (Dear ImGui 1.92 loads glyphs on demand).
DestroyContext destroys one (None: the current one) and frees its textures: call it while the rendering backend is still alive. Several contexts (e.g. two font sizes, several ImGui contexts) can live together; all the other functions act on the current one. In ImGui Bundle, ImmApp makes one for you when markdown is enabled.

Python bindings defaults:
If options is None, then its default value will be: MarkdownOptions()

destroy_context

def destroy_context(context: Optional[Context] = None) -> None
void DestroyContext(Context* context = nullptr);

set_current_context

def set_current_context(context: Context) -> None
void SetCurrentContext(Context* context);

get_current_context

def get_current_context() -> Context
Context* GetCurrentContext();

set_assets_folder

def set_assets_folder(folder: str) -> None
void SetAssetsFolder(const std::string& folder);

The folder where the default host reads the assets (fonts, images) from the file system, when they are not embedded in the binary. Default: the current directory.

Rendering files

render_file

def render_file(path: str, target: str = '') -> None
void RenderFile(const std::string& path, const std::string& target = "");

Renders ![[path#target]]: target is a section (“Intro”), its code (“Escape#code”), a code region, a heading of a markdown document, or empty (the whole file). The path is looked up in the assets first, then on the file system: a source file renders its own narrative with RICHMD_RENDER_THIS_FILE(“Intro”) (C++) or rich_md.render_this_file(“Intro”) (Python).

render_file() renders a section, a code region or a whole file: a program renders its own narrative with RICHMD_RENDER_THIS_FILE. The syntax and the resolver: narrative_programming.h.

Extensions

register_fenced_block_renderer

def register_fenced_block_renderer(language: str, renderer: Callable[[str], None]) -> None
void RegisterFencedBlockRenderer(const std::string& language, std::function<void(const std::string& code)> renderer);

Renders the code blocks of a given language (mermaid, csv, ...) with your own function, instead of the code block renderer. Applies to the current context.

Your own renderers for fenced code blocks, Mermaid diagrams and links outside of markdown.

render_mermaid

def render_mermaid(source: str) -> None
void RenderMermaid(const std::string& source);

Renders a Mermaid diagram (flowchart, sequence or class diagram), as ```mermaid blocks do. A diagram that cannot be parsed is shown as code, with the error below it; so is any diagram when the library is built without IMGUI_RICHMD_WITH_MERMAID.
Limitations: a subset of Mermaid, for small and medium diagrams, with its own layout (not a copy of mermaid.js) and the colors of the ImGui style. The other diagram types, styles (classDef, style), click, themes, front matter and markdown in labels are not supported. Details: docs/mermaid.md in imgui_rich_md.

def render_text_as_link(text: str, url: str) -> None
void RenderTextAsLink(const char* text, const char* url);

Renders a link with the given text and url. Can be used outside of markdown rendering.

Style and fonts

SizedFont (class)

struct SizedFont

Note: Since v1.92, Fonts can be displayed at any size: in order to display a font at a given size, we need to call
ImGui::PushFont(font, size) (or call separately ImGui::PushFontSize)

AttributeC++
font: ImFontImFont* font;
size: floatfloat size;
SizedFont.__init__
def __init__(self) -> None

Autogenerated default constructor

get_code_font

def get_code_font() -> SizedFont
SizedFont GetCodeFont();

The markdown’s fonts, at the size that a render would use now (see Render(): they follow a pushed size)

MarkdownFontSpec (class)

struct MarkdownFontSpec
AttributeC++
italic: boolbool italic = false;
bold: boolbool bold = false;
header_level: intint headerLevel = 0;0 means no header, 1 means h1, 2 means h2, etc.
MarkdownFontSpec.__init__
def __init__(self, italic_: bool = False, bold_: bool = False, header_level_: int = 0) -> None
MarkdownFontSpec(bool italic_ = false, bool bold_ = false, int headerLevel_ = 0) :
            italic(italic_), bold(bold_), headerLevel(headerLevel_);

get_font

def get_font(font_spec: MarkdownFontSpec) -> SizedFont
SizedFont GetFont(const MarkdownFontSpec& fontSpec);
def link_color() -> ImVec4
ImVec4 LinkColor();

Capabilities

has_latex

def has_latex() -> bool
bool HasLatex();

... and

......

rendered as formulas (else shown as their source)

What this build and its host provide (available once a context exists).

has_url_images

def has_url_images() -> bool
bool HasUrlImages();

images downloaded from http(s) urls

has_code_editor

def has_code_editor() -> bool
bool HasCodeEditor();

code blocks with syntax highlighting (else plain monospaced blocks)

Legacy names

initialize_markdown

def initialize_markdown(options: Optional[MarkdownOptions] = None) -> None
void InitializeMarkdown(const MarkdownOptions& options = MarkdownOptions());

The former names, kept for existing code.

The former names: InitializeMarkdown makes a default context and makes it current (a second call does nothing); DeInitializeMarkdown destroys it.

Python bindings defaults:
If options is None, then its default value will be: MarkdownOptions()

de_initialize_markdown

def de_initialize_markdown() -> None
void DeInitializeMarkdown();

render_unindented

def render_unindented(markdown_string: str) -> None
void RenderUnindented(const std::string& markdownString);

The former name of Render

get_font_loader_function

def get_font_loader_function() -> VoidFunction
VoidFunction GetFontLoaderFunction();

Legacy: the fonts now load at the first Render(). The returned function loads them right away, for hosts that build their font atlas once (no dynamic fonts).