bezel-markdown 0.2.9

A Notion-style block document model for gpui — markdown in, markdown out
Documentation
//! Who describes a link.
//!
//! `markdown` fetches nothing. Resolving a URL's Open Graph data is an HTTP
//! request and an HTML parse, neither of which a component library has any
//! business carrying, and `wasm32-unknown-unknown` would spell both differently
//! anyway. Installed once at boot like the highlighter and read at paint: the
//! app answers from its own cache and notifies when a fetch lands.

use gpui::{AnyElement, App, Global, SharedString, Window};

/// What a bookmark paints beyond the URL it already has.
///
/// Every field is optional because a preview arrives in pieces, and a card
/// holding none of them still shows its host.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Preview {
    pub title: Option<SharedString>,
    pub description: Option<SharedString>,
    pub image: Option<SharedString>,
    pub icon: Option<SharedString>,
    /// The footer's identity where the host is not the most specific one — a
    /// repository, a subreddit. Which path names a *unit* is the app's
    /// knowledge, not this crate's.
    pub label: Option<SharedString>,
    /// An app's own mark for a link it owns, painted in the text colour where
    /// a favicon would go. A chip with one opens no hover card.
    pub glyph: Option<ui::icons::Icon>,
}

/// The card an app paints for a link it owns, in place of the bookmark — see
/// [`crate::AppExt::set_link_card`]. `None` for a link it leaves to the web
/// preview.
///
/// The element sits inside [`crate::render::PAINTED_CONTEXT`]. A press it does
/// not stop reaches the editor.
pub type LinkCard = fn(url: &str, form: crate::Form, &mut Window, &mut App) -> Option<AnyElement>;

struct InstalledCard(LinkCard);

impl Global for InstalledCard {}

pub(crate) fn set_link_card(cx: &mut App, card: LinkCard) {
    cx.set_global(InstalledCard(card));
}

pub(crate) fn card(
    url: &str,
    form: crate::Form,
    window: &mut Window,
    cx: &mut App,
) -> Option<AnyElement> {
    let card = cx.try_global::<InstalledCard>()?.0;
    card(url, form, window, cx)
}

/// `None` for a URL the caller has nothing for *yet*: the card paints its host
/// and repaints when the answer arrives.
///
/// `cx` is how the answer is found: a cache lives in the app, so a bare call
/// with only the URL would have to reach for a `static` to read its own.
/// Shared rather than exclusive because this is asked at paint — the fetch it
/// misses belongs to whatever notices the `None`, not to the paint that
/// returned it.
pub type LinkPreview = fn(url: &str, cx: &App) -> Option<Preview>;

struct Installed(LinkPreview);

impl Global for Installed {}

/// `cx.set_link_preview(my_previews)` — call once at boot. Without
/// it a bookmark shows its host and its URL, which is what a link looks like
/// before anyone has resolved it.
pub(crate) fn set_link_preview(cx: &mut App, preview: LinkPreview) {
    cx.set_global(Installed(preview));
}

pub(crate) fn of(cx: &App, url: &str) -> Option<Preview> {
    // Copied out before the call: a preview reads its own globals off the same
    // `cx` this borrows.
    let preview = cx.try_global::<Installed>()?.0;
    preview(url, cx)
}

/// The host, without its `www.` — all a card can say about a URL nobody has
/// resolved.
pub(crate) fn host(url: &str) -> &str {
    let after = url.split_once("://").map_or(url, |(_, rest)| rest);
    let host = after.split(['/', '?', '#']).next().unwrap_or(after);
    host.strip_prefix("www.").unwrap_or(host)
}