pub struct Node {
pub node_type: Option<String>,
pub attrs: Option<Map<String, Value>>,
pub content: Option<Vec<Node>>,
pub marks: Option<Vec<Mark>>,
pub text: Option<String>,
pub extra: Map<String, Value>,
}Expand description
A single Tiptap/ProseMirror node.
All structural fields are optional to faithfully distinguish “missing” from
“empty” on roundtrip. Unknown top-level keys land in Node::extra.
Fields§
§node_type: Option<String>Node type, e.g. "doc", "paragraph", "text".
attrs: Option<Map<String, Value>>Node attributes.
content: Option<Vec<Node>>Child nodes.
marks: Option<Vec<Mark>>Marks applied to this node (typically text nodes).
text: Option<String>Text payload (text nodes only).
extra: Map<String, Value>Any unknown/extra top-level fields, preserved verbatim.
Implementations§
Source§impl Node
impl Node
Sourcepub fn set_block_type(
&mut self,
path: &[usize],
new_type: impl Into<String>,
attrs: Option<Map<String, Value>>,
) -> Result<(), BlockError>
pub fn set_block_type( &mut self, path: &[usize], new_type: impl Into<String>, attrs: Option<Map<String, Value>>, ) -> Result<(), BlockError>
Change the type (and attrs) of the block at path in place, keeping its
content — unlike a wholesale Change::Replace.
attrs = None clears attrs. The root (&[]) may be retyped.
Sourcepub fn split_block(
&mut self,
path: &[usize],
at: usize,
depth: usize,
) -> Result<(), BlockError>
pub fn split_block( &mut self, path: &[usize], at: usize, depth: usize, ) -> Result<(), BlockError>
Split the block at path at child-boundary index at into two siblings:
the left keeps children [..at], a new right sibling takes [at..]
(same type/attrs/marks/extra). depth also splits that many ancestors
(ProseMirror-style), clamped at the root.
Sourcepub fn split_block_at(
&mut self,
path: &[usize],
pos: Position,
depth: usize,
) -> Result<(), BlockError>
pub fn split_block_at( &mut self, path: &[usize], pos: Position, depth: usize, ) -> Result<(), BlockError>
Split the block at path at an inline Position (materializing a
mid-text boundary first), then split like Node::split_block.
Sourcepub fn join_blocks(
&mut self,
parent: &[usize],
index: usize,
) -> Result<(), BlockError>
pub fn join_blocks( &mut self, parent: &[usize], index: usize, ) -> Result<(), BlockError>
Merge the block at parent[index] into its previous sibling
parent[index-1] (appending its content, re-merging inline text at the
seam). The previous sibling’s type/attrs win on a mismatch.
Sourcepub fn wrap(
&mut self,
path: &[usize],
wrapper_type: impl Into<String>,
attrs: Option<Map<String, Value>>,
) -> Result<(), BlockError>
pub fn wrap( &mut self, path: &[usize], wrapper_type: impl Into<String>, attrs: Option<Map<String, Value>>, ) -> Result<(), BlockError>
Wrap the single block at path in a new parent of wrapper_type.
Sourcepub fn wrap_range(
&mut self,
range: &BlockRange,
wrapper_type: impl Into<String>,
attrs: Option<Map<String, Value>>,
) -> Result<(), BlockError>
pub fn wrap_range( &mut self, range: &BlockRange, wrapper_type: impl Into<String>, attrs: Option<Map<String, Value>>, ) -> Result<(), BlockError>
Wrap a contiguous run of sibling blocks (one level) in a new parent of
wrapper_type. Nested structures (e.g. bulletList > listItem) are
composed by the caller.
Source§impl Node
impl Node
Sourcepub fn element(node_type: impl Into<String>) -> Node
pub fn element(node_type: impl Into<String>) -> Node
Start an element node of node_type (no content/marks/attrs yet).
use tiptap_rusty_parser::Node;
let p = Node::element("paragraph")
.with_attr("textAlign", "center")
.with_text("hello");
assert_eq!(p.child_count(), 1);Sourcepub fn text_with_marks(
text: impl Into<String>,
marks: impl IntoIterator<Item = Mark>,
) -> Node
pub fn text_with_marks( text: impl Into<String>, marks: impl IntoIterator<Item = Mark>, ) -> Node
A text node with text and the given marks.
Sourcepub fn with_attr(self, key: impl Into<String>, value: impl Into<Value>) -> Self
pub fn with_attr(self, key: impl Into<String>, value: impl Into<Value>) -> Self
Builder: set one attr (consuming).
Sourcepub fn with_child(self, node: Node) -> Self
pub fn with_child(self, node: Node) -> Self
Builder: add a child (consuming).
Sourcepub fn with_children(self, nodes: impl IntoIterator<Item = Node>) -> Self
pub fn with_children(self, nodes: impl IntoIterator<Item = Node>) -> Self
Builder: add several children (consuming).
Source§impl Node
impl Node
Source§impl Node
impl Node
Sourcepub fn to_html(&self) -> String
pub fn to_html(&self) -> String
Render this node (and its subtree) to an HTML string with default options.
Sourcepub fn to_html_with(&self, opts: &HtmlOptions) -> String
pub fn to_html_with(&self, opts: &HtmlOptions) -> String
Render to HTML with custom HtmlOptions.
Source§impl Node
impl Node
Sourcepub fn get_mark(&self, mark_type: &str) -> Option<&Mark>
pub fn get_mark(&self, mark_type: &str) -> Option<&Mark>
Reference to the first mark of mark_type.
Sourcepub fn add_mark(&mut self, mark: Mark) -> bool
pub fn add_mark(&mut self, mark: Mark) -> bool
Add mark if no mark of that type exists yet. Returns true if added.
Sourcepub fn remove_mark(&mut self, mark_type: &str) -> usize
pub fn remove_mark(&mut self, mark_type: &str) -> usize
Remove every mark of mark_type. Returns count removed.
Sourcepub fn toggle_mark(&mut self, mark: Mark) -> bool
pub fn toggle_mark(&mut self, mark: Mark) -> bool
Toggle a mark: remove if present, else add. Returns true if now present.
Sourcepub fn set_mark_attr(
&mut self,
mark_type: &str,
key: impl Into<String>,
value: impl Into<Value>,
) -> bool
pub fn set_mark_attr( &mut self, mark_type: &str, key: impl Into<String>, value: impl Into<Value>, ) -> bool
Set an attr on the (first) mark of mark_type. Returns false if absent.
Sourcepub fn clear_marks(&mut self)
pub fn clear_marks(&mut self)
Drop all marks.
Sourcepub fn attrs_mut(&mut self) -> &mut Map<String, Value>
pub fn attrs_mut(&mut self) -> &mut Map<String, Value>
Mutable access to the attrs map, creating it if absent.
Sourcepub fn set_attr(
&mut self,
key: impl Into<String>,
value: impl Into<Value>,
) -> Option<Value>
pub fn set_attr( &mut self, key: impl Into<String>, value: impl Into<Value>, ) -> Option<Value>
Set attr key, returning the previous value if any.
Sourcepub fn remove_attr(&mut self, key: &str) -> Option<Value>
pub fn remove_attr(&mut self, key: &str) -> Option<Value>
Remove attr key, returning its value if present.
Sourcepub fn child_count(&self) -> usize
pub fn child_count(&self) -> usize
Number of direct children.
Sourcepub fn children_mut(&mut self) -> &mut Vec<Node>
pub fn children_mut(&mut self) -> &mut Vec<Node>
Mutable access to children, creating the vec if absent.
Sourcepub fn push_child(&mut self, node: Node)
pub fn push_child(&mut self, node: Node)
Append a child.
Sourcepub fn insert_child(&mut self, i: usize, node: Node)
pub fn insert_child(&mut self, i: usize, node: Node)
Insert a child at i (clamped to len).
Sourcepub fn remove_child(&mut self, i: usize) -> Option<Node>
pub fn remove_child(&mut self, i: usize) -> Option<Node>
Remove and return the child at i.
Sourcepub fn replace_child(&mut self, i: usize, node: Node) -> Option<Node>
pub fn replace_child(&mut self, i: usize, node: Node) -> Option<Node>
Replace the child at i, returning the old node.
Sourcepub fn clear_children(&mut self)
pub fn clear_children(&mut self)
Remove all children.
Sourcepub fn retain_children(&mut self, pred: impl FnMut(&Node) -> bool)
pub fn retain_children(&mut self, pred: impl FnMut(&Node) -> bool)
Retain only children matching pred.
Source§impl Node
impl Node
Sourcepub fn normalize(&mut self)
pub fn normalize(&mut self)
Normalize this subtree in place with default NormalizeOptions.
Sourcepub fn normalize_with(&mut self, opts: &NormalizeOptions)
pub fn normalize_with(&mut self, opts: &NormalizeOptions)
Normalize this subtree in place with custom NormalizeOptions.
Source§impl Node
impl Node
Sourcepub fn node_at(&self, path: &[usize]) -> Option<&Node>
pub fn node_at(&self, path: &[usize]) -> Option<&Node>
Node at path (relative to self), or None if any index is missing.
use tiptap_rusty_parser::Document;
let doc = Document::from_json_str(
r#"{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"hi"}]}]}"#,
).unwrap();
assert_eq!(doc.node_at(&[0, 0]).unwrap().get_text(), Some("hi"));
assert!(doc.node_at(&[5]).is_none());Sourcepub fn node_at_mut(&mut self, path: &[usize]) -> Option<&mut Node>
pub fn node_at_mut(&mut self, path: &[usize]) -> Option<&mut Node>
Mutable variant of Node::node_at.
Sourcepub fn path_to(&self, pred: impl FnMut(&Node) -> bool) -> Option<Vec<usize>>
pub fn path_to(&self, pred: impl FnMut(&Node) -> bool) -> Option<Vec<usize>>
Path to the first node (incl. self) matching pred, pre-order.
Returns Some(vec![]) when self matches.
use tiptap_rusty_parser::Document;
let doc = Document::from_json_str(
r#"{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"hi"}]}]}"#,
).unwrap();
let p = doc.path_to(|n| n.node_type.as_deref() == Some("text")).unwrap();
assert_eq!(p, vec![0, 0]);
assert_eq!(doc.node_at(&p).unwrap().get_text(), Some("hi"));Source§impl Node
impl Node
Sourcepub fn walk(&self, f: &mut impl FnMut(&Node))
pub fn walk(&self, f: &mut impl FnMut(&Node))
Visit self and every descendant, pre-order.
use tiptap_rusty_parser::Document;
let doc = Document::from_json_str(r#"{"type":"doc","content":[{"type":"paragraph"}]}"#).unwrap();
let mut n = 0;
doc.root().walk(&mut |_| n += 1);
assert_eq!(n, 2);Sourcepub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Node))
pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Node))
Mutable pre-order visit of self and every descendant.
Sourcepub fn find(&self, pred: impl FnMut(&Node) -> bool) -> Option<&Node>
pub fn find(&self, pred: impl FnMut(&Node) -> bool) -> Option<&Node>
First node (incl. self) matching pred, pre-order.
Sourcepub fn find_mut(&mut self, pred: impl FnMut(&Node) -> bool) -> Option<&mut Node>
pub fn find_mut(&mut self, pred: impl FnMut(&Node) -> bool) -> Option<&mut Node>
Mutable variant of Node::find.
Sourcepub fn find_all(&self, pred: impl FnMut(&Node) -> bool) -> Vec<&Node>
pub fn find_all(&self, pred: impl FnMut(&Node) -> bool) -> Vec<&Node>
All nodes (incl. self) matching pred, pre-order.
Sourcepub fn find_all_mut(
&mut self,
pred: &mut impl FnMut(&Node) -> bool,
) -> Vec<&mut Node>
pub fn find_all_mut( &mut self, pred: &mut impl FnMut(&Node) -> bool, ) -> Vec<&mut Node>
Mutable variant of Node::find_all. Collects matching &mut Node.
Sourcepub fn descendants(&self) -> Descendants<'_> ⓘ
pub fn descendants(&self) -> Descendants<'_> ⓘ
Lazy pre-order iterator over self and all descendants.
Source§impl Node
impl Node
Sourcepub fn insert_text(
&mut self,
pos: Position,
text: &str,
marks: Option<&[Mark]>,
) -> Result<(), RangeError>
pub fn insert_text( &mut self, pos: Position, text: &str, marks: Option<&[Mark]>, ) -> Result<(), RangeError>
Insert text (with optional marks) at pos in this block’s inline
content, splitting the target text node if needed and merging with
adjacent equal-mark text afterwards.
Sourcepub fn delete_range(&mut self, range: Range) -> Result<(), RangeError>
pub fn delete_range(&mut self, range: Range) -> Result<(), RangeError>
Delete everything in range, splitting text nodes at the boundaries and
removing fully-covered inline nodes. A collapsed range is a no-op.
Sourcepub fn replace_range(
&mut self,
range: Range,
text: &str,
marks: Option<&[Mark]>,
) -> Result<(), RangeError>
pub fn replace_range( &mut self, range: Range, text: &str, marks: Option<&[Mark]>, ) -> Result<(), RangeError>
Replace range with text (carrying optional marks).
Sourcepub fn add_mark_range(
&mut self,
range: Range,
mark: Mark,
) -> Result<(), RangeError>
pub fn add_mark_range( &mut self, range: Range, mark: Mark, ) -> Result<(), RangeError>
Add mark to every text node covered by range (splitting at the
boundaries first), then re-merge equal-mark neighbours.
Sourcepub fn remove_mark_range(
&mut self,
range: Range,
mark_type: &str,
) -> Result<(), RangeError>
pub fn remove_mark_range( &mut self, range: Range, mark_type: &str, ) -> Result<(), RangeError>
Remove every mark of mark_type from text nodes covered by range.
Sourcepub fn toggle_mark_range(
&mut self,
range: Range,
mark: Mark,
) -> Result<(), RangeError>
pub fn toggle_mark_range( &mut self, range: Range, mark: Mark, ) -> Result<(), RangeError>
Toggle mark over range: if every covered text node already has a
mark of that type, remove it from all; otherwise add it to all. Mirrors
the ProseMirror toggle semantics, range-scoped.
Source§impl Node
impl Node
Sourcepub fn validate(&self, schema: &Schema) -> Vec<Violation>
pub fn validate(&self, schema: &Schema) -> Vec<Violation>
Validate against schema, collecting every Violation. An empty
result means the document is valid.
use tiptap_rusty_parser::{Document, Schema, NodeSpec};
let schema = Schema::new()
.node("doc", NodeSpec::new().content(["paragraph"]))
.node("paragraph", NodeSpec::new())
.node("heading", NodeSpec::new());
let doc = Document::from_json_str(
r#"{"type":"doc","content":[{"type":"heading"}]}"#,
).unwrap();
let v = doc.validate(&schema);
assert_eq!(v.len(), 1); // heading is a known type, but not allowed as a child of docSourcepub fn is_valid(&self, schema: &Schema) -> bool
pub fn is_valid(&self, schema: &Schema) -> bool
True if the document has no schema violations.
use tiptap_rusty_parser::{Document, Schema, NodeSpec};
let schema = Schema::new().node("doc", NodeSpec::new());
let doc = Document::from_json_str(r#"{"type":"doc"}"#).unwrap();
assert!(doc.is_valid(&schema));Source§impl Node
impl Node
Sourcepub fn by_type(&self, node_type: &str) -> Vec<&Node>
pub fn by_type(&self, node_type: &str) -> Vec<&Node>
All descendants (incl. self) whose type equals node_type.
use tiptap_rusty_parser::Document;
let doc = Document::from_json_str(
r#"{"type":"doc","content":[{"type":"paragraph"},{"type":"paragraph"}]}"#,
).unwrap();
assert_eq!(doc.by_type("paragraph").len(), 2);Sourcepub fn first_by_type(&self, node_type: &str) -> Option<&Node>
pub fn first_by_type(&self, node_type: &str) -> Option<&Node>
First descendant (incl. self) whose type equals node_type, pre-order.
Sourcepub fn by_type_mut(&mut self, node_type: &str) -> Vec<&mut Node>
pub fn by_type_mut(&mut self, node_type: &str) -> Vec<&mut Node>
Mutable variant of Node::by_type.
Sourcepub fn by_mark(&self, mark_type: &str) -> Vec<&Node>
pub fn by_mark(&self, mark_type: &str) -> Vec<&Node>
All descendants (incl. self) carrying a mark of mark_type.
use tiptap_rusty_parser::Document;
let doc = Document::from_json_str(
r#"{"type":"doc","content":[{"type":"text","text":"a","marks":[{"type":"bold"}]}]}"#,
).unwrap();
assert_eq!(doc.by_mark("bold").len(), 1);Sourcepub fn by_attr(&self, key: &str, value: impl Into<Value>) -> Vec<&Node>
pub fn by_attr(&self, key: &str, value: impl Into<Value>) -> Vec<&Node>
All descendants (incl. self) whose attribute key equals value.
use tiptap_rusty_parser::Document;
let doc = Document::from_json_str(
r#"{"type":"doc","content":[{"type":"heading","attrs":{"level":1}}]}"#,
).unwrap();
assert_eq!(doc.by_attr("level", 1).len(), 1);Source§impl Node
impl Node
Sourcepub fn text_content(&self) -> String
pub fn text_content(&self) -> String
Concatenate all descendant text, with no separators.
Matches ProseMirror’s node.textContent.
use tiptap_rusty_parser::Document;
let doc = Document::from_json_str(
r#"{"type":"doc","content":[
{"type":"paragraph","content":[{"type":"text","text":"Hello "},{"type":"text","text":"world"}]}
]}"#,
).unwrap();
assert_eq!(doc.text_content(), "Hello world");Sourcepub fn text_content_with_separator(&self, sep: &str) -> String
pub fn text_content_with_separator(&self, sep: &str) -> String
Concatenate descendant text, inserting sep between adjacent block-level
siblings (a node is “block-level” if it has content and is not a text
node). Text within a block stays contiguous.
use tiptap_rusty_parser::Document;
let doc = Document::from_json_str(
r#"{"type":"doc","content":[
{"type":"paragraph","content":[{"type":"text","text":"Hello"}]},
{"type":"paragraph","content":[{"type":"text","text":"world"}]}
]}"#,
).unwrap();
assert_eq!(doc.text_content_with_separator("\n\n"), "Hello\n\nworld");Sourcepub fn char_count(&self) -> usize
pub fn char_count(&self) -> usize
Total number of Unicode scalar values across all descendant text.
Sourcepub fn word_count(&self) -> usize
pub fn word_count(&self) -> usize
Number of words across all text, via Unicode word segmentation.
Blocks are separated by a space first, so words don’t merge across block boundaries. Correct for CJK and other complex scripts.
use tiptap_rusty_parser::Document;
let doc = Document::from_json_str(
r#"{"type":"doc","content":[
{"type":"paragraph","content":[{"type":"text","text":"Hello"}]},
{"type":"paragraph","content":[{"type":"text","text":"brave world"}]}
]}"#,
).unwrap();
assert_eq!(doc.word_count(), 3);