calternal_notes_core::tasks::line
Inline checkbox lines: read-only parser and the
byte-stable status writer. A Markdown checkbox has one open in-progress
marker, so Blocked and Waiting fold to Doing for inline Tasks (#1092,
DESIGN §§31, 40). Task Notes keep those statuses in frontmatter.
What this module does
Section titled “What this module does”parse_task_lineparses a single text line (from a day-file body or atasks/child line) into aTaskLine. It is pure and read-only — it never mutates the line.set_task_line_statusis the write-side counterpart: it flips ONLY the[.]checkbox marker of the line addressed by a block-id and preserves every other byte of the file.task_root_checkbox_ordinalfinds a rich Task mirror by its persisted reminder block ID, then its legacy unanchored title. This keeps an anchored same-title child independent (#659, DESIGN §9).set_task_root_checkbox_statuswrites that mirror and leaves legacy child-only files unchanged.
The two share one checkbox-detection helper (checkbox_marker_span) so the
reader and writer ALWAYS agree on which lines are checkbox tasks and where the
marker window lives — a line the reader treats as a task is exactly the set
the writer counts for ordinals and matches for ^id.
When to call it
Section titled “When to call it”The projector (extractTaskIndex, plan 6 / T6) calls parse_task_line to
turn every checkbox line in a day/body file or a tasks/ file’s body into a
TaskLine, then assembles TaskIndexEntry rows from the results.
Anchors use the Markdown block-ID grammar (ASCII letters, digits, - and
_) so link and Task projections keep the same identity (#531).
Priority fold (4-level mapping from five emoji signifiers)
Section titled “Priority fold (4-level mapping from five emoji signifiers)”The inline Task format defines five priority emoji; calternal tracks 4 levels. The fold:
🔺→Urgent⏫→High🔼→Medium🔽→Low⏬→Low← the format’s “Lowest” is folded into our Low tier because we have no “Lowest” concept and it is semantically closest to Low.
Title stripping
Section titled “Title stripping”Root mirror readers and writers match literal frontmatter titles through one predicate; Task sigils in a Note title must not create a second Task (#940; DESIGN §40).
The title field is the residual after removing ALL of:
- the leading
\s*- [.]checkbox prefix - every emoji metadata token (
📅,🛫,⏳,➕,✅,❌,🔁) and their following date/rule value - priority emoji (
🔺,⏫,🔼,🔽,⏬) - a reference link to
tasks/<file>, arrow-prefixed or bare, in EITHER accepted spelling (#27 T11, dual-form read rule):[[tasks/<file>]](legacy wikilink) or[<text>](tasks/<file>)(the standard form the app now WRITES — spec A §C.1) ^blockidanchors#tagtokens Surrounding whitespace is trimmed from what remains.
Tags keep their original source span for title stripping and are returned in NFC form so decomposed and composed spellings share one name (#473).
Source: crates/calternal-notes-core/src/tasks/line.rs
Structs
Section titled “Structs”TaskLinePatch
Section titled “TaskLinePatch”pub struct TaskLinePatchByte-stable edits to the supported scalar fields of one anchored checkbox.
Each Some(None) removes that field; None leaves it unchanged.
Fields
pub title: Option<String>pub due: Option<Option<CivilDate>>pub scheduled: Option<Option<CivilDate>>pub start: Option<Option<CivilDate>>pub completed: Option<Option<CivilDate>>pub priority: Option<Option<TaskPriority>>
Implements: Clone, Debug, Default, PartialEq, Eq
Source: crates/calternal-notes-core/src/tasks/line.rs:590
Functions
Section titled “Functions”remove_task_line
Section titled “remove_task_line”pub fn remove_task_line(text: &str, block_id: &str) -> Result<String, String>Remove exactly one checkbox line addressed by its explicit block ID.
The writer rejects missing or duplicate IDs so a stale CalDAV resource cannot delete an arbitrary sibling. It preserves the line endings and every byte outside the selected line.
Source: crates/calternal-notes-core/src/tasks/line.rs:642
set_task_line_properties
Section titled “set_task_line_properties”pub fn set_task_line_properties( text: &str, block_id: &str, patch: &TaskLinePatch,) -> Result<String, String>Update fields on the checkbox with this explicit block ID. The writer does not accept ordinal fallbacks because CalDAV resource identities must remain stable when a sibling checkbox is inserted or removed.
Source: crates/calternal-notes-core/src/tasks/line.rs:602
set_task_line_status
Section titled “set_task_line_status”pub fn set_task_line_status( text: &str, block_id: &str, status: TaskStatus,) -> Result<String, String>Flip ONLY the checkbox marker of the task line addressed by block_id,
preserving every other byte of text.
This is the write-side counterpart to [parse_task_line]: the UI calls it to
tick/untick an inline checkbox by its block-id. It round-trips with the
byte-stable frontmatter writer.
Status → marker
Section titled “Status → marker”Todo→[ ], Doing/Blocked/Waiting→[/], Done→[x], and
Cancelled→[-]. Inline checkboxes have no separate Blocked or Waiting
marker, so those states fold to the Markdown in-progress marker. Task Notes
retain the exact status in their frontmatter (#1092, DESIGN §§31, 40).
Addressing
Section titled “Addressing”block_id is matched against a checkbox line’s trailing ^<id>. If no line
carries that literal id AND block_id has the form L<n>, it addresses the
n-th checkbox line, 0-based — the ${source}#L${ordinal} taskId fallback
(contract §3). A literal ^L<n> always wins over the ordinal interpretation.
No match at all → Ok(text.to_string()) unchanged (a no-op; the caller logs).
Byte-stability
Section titled “Byte-stability”We splice: unchanged prefix + the new marker + unchanged suffix, using the
located byte range [open, close) — never a hardcoded width. For the ASCII
markers this writer emits ([ ], [x], [/], [-]) that window is 3 bytes,
but the splice is driven by the detected range, not the constant. Only the
[.] window on the matched line is touched — emoji, dates, tags, the block-id,
the line’s EOL, and every other line are preserved verbatim. Idempotent: if the
window already equals the target marker we return the input unchanged
(byte-identical, no splice).
Source: crates/calternal-notes-core/src/tasks/line.rs:397
set_task_root_checkbox_status
Section titled “set_task_root_checkbox_status”pub fn set_task_root_checkbox_status( text: &str, root_title: &str, status: TaskStatus,) -> Result<String, String>Set the checkbox marker for a rich Task’s generated root mirror.
The explicit root reminder ID identifies an anchored mirror; legacy files fall back to an unanchored title match. If neither exists, a child-only Task file stays unchanged (#659, DESIGN §§9, 41).
Source: crates/calternal-notes-core/src/tasks/line.rs:576
set_task_root_checkbox_title
Section titled “set_task_root_checkbox_title”pub fn set_task_root_checkbox_title( text: &str, old_title: &str, new_title: &str,) -> Result<String, String>Rename the root checkbox that mirrors a rich Task’s frontmatter title.
Prefer the persisted root reminder ID, then fall back to an unanchored title match. A same-title anchored child stays unchanged. The splice keeps line endings and task metadata intact.
Source: crates/calternal-notes-core/src/tasks/line.rs:527
task_root_checkbox_status
Section titled “task_root_checkbox_status”pub fn task_root_checkbox_status(text: &str, root_title: &str) -> Option<TaskStatus>Read the marker from the explicit root checkbox or its legacy unanchored mirror.