pub struct Editor { /* private fields */ }Expand description
A span-splice editor over a document: applies lossless, in-place edits and
reparses after each one, so node addressing stays valid as the document
evolves. Every op is addressed by a locator — a dot-separated index path
("0.3.1") or a selector that must match exactly one node
(heading("Status")). A failed edit leaves the document unchanged.
Implementations§
Source§impl Editor
impl Editor
Sourcepub fn new(input: &[u8], format: Format) -> Result<Self, Error>
pub fn new(input: &[u8], format: Format) -> Result<Self, Error>
Create an editor over a private copy of input, parsed as format with
default options.
pub fn new_str(input: &str, format: Format) -> Result<Self, Error>
Sourcepub fn new_ext(
input: &[u8],
format: Format,
extensions: MarkdownExtensions,
) -> Result<Self, Error>
pub fn new_ext( input: &[u8], format: Format, extensions: MarkdownExtensions, ) -> Result<Self, Error>
Like Editor::new, plus Markdown extensions to enable (ignored for
other formats). The editor reparses with these after every edit, so a
directive-bearing document stays parseable — needed before
Editor::filter can match directive[...] selectors.
Sourcepub fn replace(&mut self, locator: &str, text: &str) -> Result<(), Error>
pub fn replace(&mut self, locator: &str, text: &str) -> Result<(), Error>
Replace the whole source of the located node with text.
Sourcepub fn replace_content(
&mut self,
locator: &str,
text: &str,
) -> Result<(), Error>
pub fn replace_content( &mut self, locator: &str, text: &str, ) -> Result<(), Error>
Replace the interior (between-delimiters content) of the located container.
Sourcepub fn insert_before(&mut self, locator: &str, text: &str) -> Result<(), Error>
pub fn insert_before(&mut self, locator: &str, text: &str) -> Result<(), Error>
Insert text immediately before the located node.
Sourcepub fn insert_after(&mut self, locator: &str, text: &str) -> Result<(), Error>
pub fn insert_after(&mut self, locator: &str, text: &str) -> Result<(), Error>
Insert text immediately after the located node.
Sourcepub fn insert_child(
&mut self,
locator: &str,
index: usize,
text: &str,
) -> Result<(), Error>
pub fn insert_child( &mut self, locator: &str, index: usize, text: &str, ) -> Result<(), Error>
Insert text as the index-th child of the located container (an index
at or past the child count appends).
Sourcepub fn delete(&mut self, locator: &str) -> Result<(), Error>
pub fn delete(&mut self, locator: &str) -> Result<(), Error>
Delete the located node (removes exactly its span; no whitespace cleanup).
Sourcepub fn delete_smart(&mut self, locator: &str) -> Result<(), Error>
pub fn delete_smart(&mut self, locator: &str) -> Result<(), Error>
Delete the located node, tidying surrounding blank lines for a whole-line (block) node; an inline node degrades to the exact delete.
Sourcepub fn unwrap_node(&mut self, locator: &str) -> Result<(), Error>
pub fn unwrap_node(&mut self, locator: &str) -> Result<(), Error>
Unwrap the located node: replace it with its interior (drop the wrapper,
keep the children) — e.g. peel a :::vis{...} container. A node with no
interior (a leaf, or an empty container) is removed.
Sourcepub fn filter(
&mut self,
drop: &str,
keep: Option<&str>,
unwrap_kept: bool,
) -> Result<(), Error>
pub fn filter( &mut self, drop: &str, keep: Option<&str>, unwrap_kept: bool, ) -> Result<(), Error>
Prune the document in place: remove every node matching the drop
selector except those also matching keep (None spares nothing),
then — if unwrap_kept — unwrap the survivors. Read the result with
Editor::source.
Sourcepub fn source_str(&mut self) -> Result<String, Error>
pub fn source_str(&mut self) -> Result<String, Error>
The editor’s current source bytes as a UTF-8 string.
Sourcepub fn ast_json(&mut self) -> Result<Vec<u8>, Error>
pub fn ast_json(&mut self) -> Result<Vec<u8>, Error>
Encode the editor’s current tree as pretty-printed JSON — the live
counterpart of Document::ast_json, for inspecting between edits.
Sourcepub fn query(&mut self, selector: &str) -> Result<Vec<QueryMatch>, Error>
pub fn query(&mut self, selector: &str) -> Result<Vec<QueryMatch>, Error>
Resolve a selector against the editor’s current tree — the live
counterpart of Document::query.
Sourcepub fn edit_range(
&mut self,
start: usize,
end: usize,
text: &str,
) -> Result<Change, Error>
pub fn edit_range( &mut self, start: usize, end: usize, text: &str, ) -> Result<Change, Error>
Splice [start, end) of the current source with text, reparse, and
return the Change the edit produced — the offset-addressed primitive
a caret editor is built on: a keystroke is edit_range(c, c, "x"),
backspace edit_range(c - 1, c, ""), a selection replace
edit_range(a, b, s). start <= end <= source length, else
Error::InvalidArgument. A reparse-breaking edit is rolled back and
returns Error::EditConflict, leaving the document untouched.
Sourcepub fn last_change(&mut self) -> Option<Change>
pub fn last_change(&mut self) -> Option<Change>
The byte effect of the last successful edit — including the locator ops
(Editor::replace, Editor::delete_smart, …), so any edit can
re-anchor a caret without re-diffing. None before the first successful
edit. (A multi-splice op such as Editor::filter reports only its
final splice.)
Sourcepub fn undo(&mut self) -> Result<Option<Change>, Error>
pub fn undo(&mut self) -> Result<Option<Change>, Error>
Undo the last edit step, restoring the previous source and reparsing.
Returns the Change the undo produced (current → restored) so a caret
can re-anchor, or None when there’s nothing to undo. History accrues
across every successful edit that funnels through the splice primitive.
Sourcepub fn redo(&mut self) -> Result<Option<Change>, Error>
pub fn redo(&mut self) -> Result<Option<Change>, Error>
Redo the most recently undone edit step; the inverse of Editor::undo.
Returns None when the redo stack is empty (nothing undone, or a fresh
edit has invalidated it).
Sourcepub fn coalesce_last_undo(&mut self) -> Result<(), Error>
pub fn coalesce_last_undo(&mut self) -> Result<(), Error>
Fold the most recent edit into the undo step before it, so a caret editor
can coalesce a run of keystrokes into a single undo. Call right after an
edit_range that continues a run (same kind, no intervening caret move);
a no-op unless there are at least two steps to merge.
Sourcepub fn nodes(&mut self) -> Result<Vec<FlatNode>, Error>
pub fn nodes(&mut self) -> Result<Vec<FlatNode>, Error>
Snapshot the current tree as a flat FlatNode array (the JSON-free
read path for a renderer), indexed so nodes[i].id == NodeId(i). Walk it
via the parent/first_child/next_sibling links; the root is the node
whose parent is None.
Sourcepub fn node_at(&mut self, offset: usize) -> Result<Option<QueryMatch>, Error>
pub fn node_at(&mut self, offset: usize) -> Result<Option<QueryMatch>, Error>
The deepest node whose span contains byte offset (with offset equal
to the source length treated as inside the root) — mouse hit-testing and
cursor context. Ok(None) if no node covers the offset;
Error::InvalidArgument if offset exceeds the source length.
Sourcepub fn ancestors_at(&mut self, offset: usize) -> Result<Vec<QueryMatch>, Error>
pub fn ancestors_at(&mut self, offset: usize) -> Result<Vec<QueryMatch>, Error>
The chain of nodes containing byte offset, root-first down to the
deepest (the node Editor::node_at returns) — the ancestor path for a
breadcrumb or context-scoped edit. Empty if no node covers the offset.
Sourcepub fn wrap_range(
&mut self,
start: usize,
end: usize,
kind: InlineKind,
) -> Result<Change, Error>
pub fn wrap_range( &mut self, start: usize, end: usize, kind: InlineKind, ) -> Result<Change, Error>
Wrap [start, end) with kind’s delimiters — the unconditional half of
the inline toolbar (always adds a mark; *word* → **word** stacks).
Error::UnsupportedFormat if the document’s format can’t spell kind
(e.g. a Markdown InlineKind::Mark); Error::InvalidArgument for a
bad range; Error::EditConflict if the result doesn’t reparse.
Sourcepub fn toggle_inline(
&mut self,
start: usize,
end: usize,
kind: InlineKind,
) -> Result<Change, Error>
pub fn toggle_inline( &mut self, start: usize, end: usize, kind: InlineKind, ) -> Result<Change, Error>
Toggle kind over [start, end): remove the mark if the range already
is a node of kind (its whole span or its rendered interior), else
wrap it — a rich editor’s Cmd-B. Same error rules as
Editor::wrap_range.
Sourcepub fn set_block(
&mut self,
offset: usize,
kind: BlockKind,
) -> Result<Change, Error>
pub fn set_block( &mut self, offset: usize, kind: BlockKind, ) -> Result<Change, Error>
Convert the innermost heading/paragraph covering byte offset to kind,
rewriting its leading marker while keeping its inline content (the
toolbar’s H1…H6 / Body switch). Djot and Markdown only, else
Error::UnsupportedFormat; Error::NotFound if no heading/paragraph
covers offset; Error::InvalidArgument for a heading level outside
1–6.