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.