Skip to content

calternal_imap::projection

Lossless Apple text edit mapping (#428, DESIGN §9). The saved Markdown, visible text, and source spans form one immutable base. Text patches keep written syntax. Representable block and mark edits use bounded semantic patches (#644/#645). Ambiguous or overlapping edits retain both sources for conflict recovery; unchanged Markdown stays byte-exact.

Source: crates/calternal-imap/src/projection.rs

pub struct Projection

Durable projection base; the caller keeps it in per-User internal files (D9).

Fields

  • pub html: String

Implements: Debug, Clone, Serialize, Deserialize

pub fn new(source: &str) -> Result<Self, &'static str>

Render supported GFM with safe URLs. Raw HTML is readable escaped text, except the four inert underline tags required by the Note grammar.

pub fn merge_edit(&self, current: &str, incoming: &str) -> Result<Merge, &'static str>

Apply representable Apple block and mark edits (#644/#645). The old span mapper remains the first choice because it retains source syntax. Structural patches own only changed blocks; unchanged bytes and all frontmatter stay in place. An overlapping current edit keeps both.

pub fn merge(&self, current: &str, incoming: &str) -> Result<Merge, &'static str>

Merge changed Apple text into current Markdown without serializing it. Concurrent changes outside the edited spans survive byte-for-byte.

Source: crates/calternal-imap/src/projection.rs:30

pub enum Merge

A clean patch or the two intact sources needed for conflict recovery (#428 D8).

Variants

  • Applied(String)
  • Conflict { current: String, incoming: String }

Implements: Debug, PartialEq, Eq

Source: crates/calternal-imap/src/projection.rs:23

pub fn apple_blocks(html: &str) -> Vec<String>

Apple writes a Note’s lines as top-level text followed by <div> lines: Title<div>Body</div>. HTML-to-Markdown converters join those into one paragraph (“TitleBody”), changing the words (#428 live Mac run). This splits the body into blocks: each run of top-level inline content and each plain <div> becomes one <p>, divs that hold blocks are split recursively, and other block elements are kept as written. The caller converts each block separately and joins them with blank lines. Imports use these blocks; #644/#645 also compare their Markdown meaning before applying patches to changed source ranges. Unchanged source is not rewritten.

Source: crates/calternal-imap/src/projection.rs:774

pub fn apple_markdown(source: &str) -> Result<String, &'static str>

Convert the bounded, inert Apple subset to Markdown (#645). DOM parsing makes aliases and attribute spelling irrelevant. Underline uses the Note grammar’s inert <u> form; unsupported structures stay on the span mapper.

Source: crates/calternal-imap/src/projection.rs:1050

pub fn visible_html(source: &str) -> Result<String, &'static str>

Read visible text in DOM order; block and explicit line boundaries are text. The Notes provider also uses this bounded reader for imported titles (#428). Active elements and excessive nesting are refused before an edit can apply.

Source: crates/calternal-imap/src/projection.rs:663

pub const MAX_HTML_DEPTH: usize

Bound accepted HTML nesting before walking text nodes.

Source: crates/calternal-imap/src/projection.rs:18

pub const MAX_PROJECTION_BYTES: usize

Bound DOM allocation and diff work independently of the transport’s limit.

Source: crates/calternal-imap/src/projection.rs:16