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
Structs
Section titled “Structs”Projection
Section titled “Projection”pub struct ProjectionDurable projection base; the caller keeps it in per-User internal files (D9).
Fields
pub html: String
Implements: Debug, Clone, Serialize, Deserialize
Projection::new
Section titled “Projection::new”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.
Projection::merge_edit
Section titled “Projection::merge_edit”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.
Projection::merge
Section titled “Projection::merge”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 MergeA 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
Functions
Section titled “Functions”apple_blocks
Section titled “apple_blocks”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
apple_markdown
Section titled “apple_markdown”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
visible_html
Section titled “visible_html”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
Constants
Section titled “Constants”MAX_HTML_DEPTH
Section titled “MAX_HTML_DEPTH”pub const MAX_HTML_DEPTH: usizeBound accepted HTML nesting before walking text nodes.
Source: crates/calternal-imap/src/projection.rs:18
MAX_PROJECTION_BYTES
Section titled “MAX_PROJECTION_BYTES”pub const MAX_PROJECTION_BYTES: usizeBound DOM allocation and diff work independently of the transport’s limit.