bezel

Patterns / Media

Document

Markdown apps/gallery/src/patterns/document.rs

doc.blocks
    .iter()
    .filter_map(|block| match &block.kind {
        BlockKind::Heading { level, text } => Some((*level, text.text.clone())),
        _ => None,
    })
    .collect()

The outline is a filter, not a walk: a Doc is a flat list of blocks carrying their own indent, so the table of contents is one pass. The Source segment shows serialize(&doc) rather than the string the file holds, and it matches byte for byte.

Marks of your own

let marks = markdown::Marks::new().with("highlight", "==").with("underline", "++");

let doc = markdown::parse_with("a ==lit== word", &marks);
assert_eq!(markdown::serialize_with(&doc, &marks), "a ==lit== word");

Mark is closed, because each of its variants is something CommonMark already spells. Underline, highlight and colour are not, so an app registers them.

API

// markdown — pure, so the registry is a parameter rather than a global.

pub fn parse_with(source: &str, marks: &Marks) -> Doc;
pub fn serialize_with(doc: &Doc, marks: &Marks) -> String;

/// The pair a caret crosses on. Both put a sentinel where the caret is, so
/// neither can drift from the serializer or parser it rides on.
pub fn parse_at(source: &str, offset: usize, marks: &Marks) -> (Doc, Cursor);

/// `parse`, keeping where each block came from. The ranges partition the
/// source — first starts at 0, each ends where the next begins, last ends at
/// `source.len()` — so re-serializing the blocks you edited and splicing
/// `source[range]` for the rest gives the untouched bytes back exactly.
pub fn parse_ranges(source: &str) -> ParsedDoc;  // { doc, block_ranges }
pub fn serialize_at(doc: &Doc, at: Cursor, marks: &Marks) -> (String, usize);

// The gpui-side half the editing surface reads. `set_mark_paint` is paint only
// — colour, background, weight, italic, underline, strike. A name nothing
// paints round trips and reads as the text it wraps.
pub trait AppExt {
    fn set_marks(&mut self, marks: Marks);
    fn set_mark_paint(&mut self, paint: Painter);
    /// Long fence lines wrap by default.
    fn set_markdown_layout(&mut self, layout: Layout);
}

/// Classifies markdown *source* without a grammar, which is what gives a
/// source view colour in a browser build.
pub fn source_spans(source: &str) -> Vec<(Range<usize>, HighlightKind)>;

/// `toggle` makes a task block's checkbox a control: `Toggle::Handled` has the
/// box take the press, stop it, and hand you the block it belongs to, and
/// `Toggle::HitTested` paints it as a control and leaves the press to you.
/// `copy` is whether a fence paints the button that copies its text. `render`
/// and `markdown` leave the toggle unset, and the box paints as a marker; a
/// document with no toggle and `CopyButton::Hidden` holds no listener at all.
pub struct Editing<'a> {
    pub toggle: Option<Toggle>,
    pub copy: CopyButton,
    /* ... */
}

// ...

A registered mark cannot reach across a line break, mean anything inside a fence, code span or link destination, or sit in a picture's caption. Its delimiters are lifted out before CommonMark sees the source, which is the only place == and \=\= still differ.

A registered mark cannot reach across a line break, mean anything inside a fence, code span or link destination, or sit in a picture's caption. Its delimiters are lifted out before CommonMark sees the source, which is the only place == and \=\= still differ.

The source is at apps/gallery/src/patterns/document.rs. Copy the file.

Document