onetaskgraph_plugin_api/section.rs
1//! What a source says about the headings of a record it stores, and the markup a body is
2//! written and read with where its destination needs some to address a heading.
3//!
4//! Both exist for a copy's section links — a link to one heading of another record, or of
5//! the same one. How each destination spells such a link is decided once, in the engine,
6//! and never here: a plugin only reports what its backend stores ([`StoredHeading`]) and
7//! applies the markup it is handed ([`BodyMarkup`]), so it holds no copy of any form.
8
9use std::sync::Arc;
10
11/// One heading of a record, as its backend stores it: its text, and the id the backend gave
12/// it.
13///
14/// Reported only by a backend that assigns its headings ids of its own — Linear's editor
15/// state gives every heading node an `id` attribute — and in the order the headings appear
16/// in the record, so the n-th heading with one text is the n-th entry with that text.
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct StoredHeading {
19 /// The heading's text, without its leading `#` marks or any inline formatting.
20 pub text: String,
21 /// The id its backend stores the heading under.
22 // llmlint: ignore[invalid_states_unrepresentable] The id is whatever a backend stores, and the contract crate states no backend's id grammar; a plugin keeps only well-formed ids (Linear's decoder keeps hex ids carrying 8 hex characters) and the engine's form checks the hex it writes, so a newtype here would only move that check into a crate every plugin rebuilds against.
23 pub id: String,
24}
25
26/// Markup a destination's bodies carry for a reader to address their headings, which the
27/// engine hands a source when it builds it.
28///
29/// A source given one applies [`written`](Self::written) to every body it sends its backend
30/// and [`read`](Self::read) to every body it reads back, so what the engine reads through
31/// the source is the body as it was authored. Defaulted away entirely: a source given none
32/// stores what it is given.
33pub trait BodyMarkup: Send + Sync {
34 /// `content` as the backend is sent it.
35 fn written(&self, content: &str) -> String;
36 /// `content` read from the backend, with exactly the markup [`written`](Self::written)
37 /// adds removed.
38 fn read(&self, content: &str) -> String;
39}
40
41/// A shared [`BodyMarkup`], as a source holds the one it was handed.
42pub type SharedBodyMarkup = Arc<dyn BodyMarkup>;