markdown/block.rs
1//! Who paints a fenced block.
2//!
3//! A consumer that needs a block of its own — a chart, a diagram, an embed —
4//! reaches for this rather than for a new [`crate::BlockKind`]. The vocabulary
5//! stays closed because markdown is the wire form and a new kind would have to
6//! own a syntax; a fence already has one. It round trips byte for byte, holds a
7//! caret in [`crate::Part::Code`], and on a build that installs nothing it
8//! paints the source it always did.
9//!
10//! Installed once at boot like the highlighter, and read at paint.
11
12use gpui::{AnyElement, App, Global, Window};
13
14/// Paints the block a fence's info string names, or `None` to leave it to the
15/// ordinary code block.
16///
17/// One answer for a language nothing paints, a renderer that has not been
18/// installed, and a renderer that looked at the code and declined.
19pub type BlockRenderer =
20 fn(language: &str, code: &str, &mut Window, &mut App) -> Option<AnyElement>;
21
22struct Installed(BlockRenderer);
23
24impl Global for Installed {}
25
26/// `markdown::set_block_renderer(cx, my_blocks)` — call once at boot.
27pub fn set_block_renderer(cx: &mut App, renderer: BlockRenderer) {
28 cx.set_global(Installed(renderer));
29}
30
31pub(crate) fn render(
32 language: Option<&str>,
33 code: &str,
34 window: &mut Window,
35 cx: &mut App,
36) -> Option<AnyElement> {
37 // Copied out before the call: the renderer reads the theme and its own
38 // globals off the same `cx` this borrows.
39 let renderer = cx.try_global::<Installed>()?.0;
40 renderer(language?, code, window, cx)
41}