pub struct TextDocument { /* private fields */ }Expand description
A rich text document.
Owns the backend (database, event hub, undo/redo manager) and provides
document-level operations. All cursor-based editing goes through
TextCursor, obtained via cursor() or
cursor_at().
Internally uses Arc<Mutex<...>> so that multiple TextCursors can
coexist and edit concurrently. Cloning a TextDocument creates a new
handle to the same underlying document (like Qt’s implicit sharing).
Implementations§
impl TextDocument
Test-only accessor for the underlying rope-backed store. Not part of the stable public API.
Source§impl TextDocument
impl TextDocument
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a new, empty document.
§Panics
Panics if the database context cannot be created (e.g. filesystem error).
Use TextDocument::try_new for a fallible alternative.
Sourcepub fn set_plain_text(&self, text: &str) -> Result<()>
pub fn set_plain_text(&self, text: &str) -> Result<()>
Replace the entire document with plain text. Clears undo history.
Sourcepub fn to_plain_text(&self) -> Result<String>
pub fn to_plain_text(&self) -> Result<String>
Export the entire document as plain text, in reading order.
This is the human-readable view: prose only. Embedded objects (a table) contribute
their content but not the U+FFFC anchor the document holds where they sit — which is
what you want for a cat-style export, and is why the crate’s fast path bails the
moment a table exists.
Do not compute offsets from this string. It is deliberately not
character-for-character the text a search runs against: that text carries the object
anchors, so a position taken here is short by two characters per preceding table. For
an addressable view — one whose offsets find_all and
replace_text agree with — use
djot_to_plain_text, which is pinned to match the
document’s own search text exactly.
The two are allowed to differ in that one respect and no other; in particular they
agree on order. They did not always: this export used to hoist every blockquote’s
prose to the end of the document ("> a0\n\na" came back as "a\na0"), because it
concatenated frames in creation order instead of sorting all blocks by
document_position. See plain_text_order_tests.
Sourcepub fn set_markdown(
&self,
markdown: &str,
) -> Result<Operation<MarkdownImportResult>>
pub fn set_markdown( &self, markdown: &str, ) -> Result<Operation<MarkdownImportResult>>
Replace the entire document with Markdown. Clears undo history.
This is a long operation. Returns a typed Operation handle.
Sourcepub fn to_markdown(&self) -> Result<String>
pub fn to_markdown(&self) -> Result<String>
Export the entire document as Markdown.
Sourcepub fn set_djot(&self, djot: &str) -> Result<Operation<DjotImportResult>>
pub fn set_djot(&self, djot: &str) -> Result<Operation<DjotImportResult>>
Replace the entire document with djot markup. Clears undo history.
This is a long operation. Returns a typed Operation handle.
Sourcepub fn set_djot_with_options(
&self,
djot: &str,
options: DjotImportOptions,
) -> Result<Operation<DjotImportResult>>
pub fn set_djot_with_options( &self, djot: &str, options: DjotImportOptions, ) -> Result<Operation<DjotImportResult>>
Replace the entire document with djot markup, selecting which optional
block attributes (alignment, line height, direction, non-breakable
lines, background color) are applied via options. Clears undo history.
This is a long operation. Returns a typed Operation handle.
Sourcepub fn set_djot_sync(&self, djot: &str) -> Result<DjotImportResult>
pub fn set_djot_sync(&self, djot: &str) -> Result<DjotImportResult>
Replace the entire document with djot markup, synchronously, on the calling thread. Clears undo history.
This is the right call for loading a document’s initial content — the
case where the caller is going to block for the result anyway.
set_djot starts a long operation: it spawns a thread,
and the caller then blocks in Operation::wait until that thread
publishes. That round trip is pure overhead when there is no frame loop to
keep responsive, and it does not shrink with the input — an empty
document costs the same thread spawn and hand-off as a full one. Loading N
documents in a loop paid it N times.
Prefer set_djot when the import is genuinely long and
the caller must stay responsive (it reports progress and can be
cancelled); prefer this when the caller just wants the content in.
Observationally equivalent to set_djot(..).wait() — same import, same
DocumentReset, same cache/block bookkeeping — except that, having no
operation, it emits no LongOperation* events and cannot be cancelled.
Sourcepub fn set_djot_sync_with_options(
&self,
djot: &str,
options: DjotImportOptions,
) -> Result<DjotImportResult>
pub fn set_djot_sync_with_options( &self, djot: &str, options: DjotImportOptions, ) -> Result<DjotImportResult>
As set_djot_sync, selecting which optional block
attributes are applied via options.
Sourcepub fn to_djot_with_options(&self, options: DjotExportOptions) -> Result<String>
pub fn to_djot_with_options(&self, options: DjotExportOptions) -> Result<String>
Export the entire document as djot markup, selecting which optional block
attributes (alignment, line height, direction, non-breakable lines,
background color) are emitted via options.
Sourcepub fn set_html(&self, html: &str) -> Result<Operation<HtmlImportResult>>
pub fn set_html(&self, html: &str) -> Result<Operation<HtmlImportResult>>
Replace the entire document with HTML. Clears undo history.
This is a long operation. Returns a typed Operation handle.
Sourcepub fn to_latex(
&self,
document_class: &str,
include_preamble: bool,
) -> Result<String>
pub fn to_latex( &self, document_class: &str, include_preamble: bool, ) -> Result<String>
Export the entire document as LaTeX.
Sourcepub fn to_docx(&self, output_path: &str) -> Result<Operation<DocxExportResult>>
pub fn to_docx(&self, output_path: &str) -> Result<Operation<DocxExportResult>>
Export the entire document as DOCX to a file path.
This is a long operation. Returns a typed Operation handle.
Sourcepub fn to_docx_with_options(
&self,
output_path: &str,
options: DocxExportOptions,
) -> Result<Operation<DocxExportResult>>
pub fn to_docx_with_options( &self, output_path: &str, options: DocxExportOptions, ) -> Result<Operation<DocxExportResult>>
As to_docx, but with page geometry + base typography overrides — a
manuscript style (page size, margins, body font, line spacing, first-line indent,
alignment, and an optional page-number header). Per-block RTL is emitted automatically
from each block’s own direction, independent of these options.
Sourcepub fn to_epub(&self, output_path: &str) -> Result<Operation<EpubExportResult>>
pub fn to_epub(&self, output_path: &str) -> Result<Operation<EpubExportResult>>
Export the entire document as an EPUB 3 file to a file path.
This is a long operation. Returns a typed Operation handle.
Sourcepub fn to_epub_with_options(
&self,
output_path: &str,
options: EpubExportOptions,
) -> Result<Operation<EpubExportResult>>
pub fn to_epub_with_options( &self, output_path: &str, options: EpubExportOptions, ) -> Result<Operation<EpubExportResult>>
As to_epub, but with book-level metadata (title, author, language,
reading direction). The document is split into chapters at the shallowest heading level
present (e.g. every top-level # Chapter heading) — see
EpubExportOptions for details.
Sourcepub fn to_pdf(
&self,
output_path: &str,
options: PdfExportOptions,
) -> Result<Operation<PdfExportResult>>
pub fn to_pdf( &self, output_path: &str, options: PdfExportOptions, ) -> Result<Operation<PdfExportResult>>
Export the entire document as a PDF file, using the given options (page geometry, typography, embedded font bytes, base language/direction).
This is a long operation. Returns a typed Operation handle.
Requires the pdf cargo feature on text-document (which forwards to frontend’s and
document_io’s own pdf features). If it was not enabled at compile time, this returns
Err(DocumentError::Unsupported(..)) immediately rather than attempting the export — no
#[cfg] is needed at the call site either way.
Sourcepub fn to_pdf_with_options(
&self,
_output_path: &str,
_options: PdfExportOptions,
) -> Result<Operation<PdfExportResult>>
pub fn to_pdf_with_options( &self, _output_path: &str, _options: PdfExportOptions, ) -> Result<Operation<PdfExportResult>>
As to_pdf, when the pdf cargo feature was not enabled at compile
time — returns DocumentError::Unsupported immediately, without starting an operation
or touching the backend at all.
Sourcepub fn cursor(&self) -> TextCursor
pub fn cursor(&self) -> TextCursor
Create a cursor at position 0.
Sourcepub fn cursor_at(&self, position: usize) -> TextCursor
pub fn cursor_at(&self, position: usize) -> TextCursor
Create a cursor at the given position. If position falls
inside an extended grapheme cluster (decomposed accents, ZWJ
emoji, skin-tone sequences, flag pairs), the cursor snaps
forward to the end of the containing cluster so subsequent
NextCharacter/PreviousCharacter round-trips remain identity.
Sourcepub fn stats(&self) -> DocumentStats
pub fn stats(&self) -> DocumentStats
Get document statistics. O(1) — reads cached values.
Sourcepub fn character_count(&self) -> usize
pub fn character_count(&self) -> usize
Get the total character count. O(1) — reads cached value.
Sourcepub fn block_count(&self) -> usize
pub fn block_count(&self) -> usize
Get the number of blocks (paragraphs). O(1) — reads cached value.
Sourcepub fn text_at(&self, position: usize, length: usize) -> Result<String>
pub fn text_at(&self, position: usize, length: usize) -> Result<String>
Get text at a position for a given length.
Sourcepub fn find_element_at_position(
&self,
position: usize,
) -> Option<(u64, usize, usize)>
pub fn find_element_at_position( &self, position: usize, ) -> Option<(u64, usize, usize)>
Find the inline segment containing position and return its
stable element id (synthesized from (block_id, byte_start)
via common::format_runs::synth_element_id) together with the
segment’s absolute start position and the character offset of
position within the segment. Used by accessibility layers to
convert a document-absolute character position into the
(element_id, character_index_in_run) coordinate space
AccessKit’s TextPosition expects.
Returns None when the position is outside the document.
Returns the element at position position - 1 when position
falls exactly on an element boundary, matching the “cursor
belongs to the preceding element at a boundary” convention
used throughout text-document.
Sourcepub fn block_at(&self, position: usize) -> Result<BlockInfo>
pub fn block_at(&self, position: usize) -> Result<BlockInfo>
Get info about the block at a position. O(log n).
Sourcepub fn block_format_at(&self, position: usize) -> Result<BlockFormat>
pub fn block_format_at(&self, position: usize) -> Result<BlockFormat>
Get the block format at a position.
Sourcepub fn flow(&self) -> Vec<FlowElement>
pub fn flow(&self) -> Vec<FlowElement>
Walk the main frame’s visual flow in document order.
Returns the top-level flow elements — blocks, tables, and
sub-frames — in the order defined by the main frame’s
child_order. Table cell contents are NOT included here;
access them through TextTableCell::blocks().
This is the primary entry point for layout initialization.
Sourcepub fn block_by_id(&self, block_id: usize) -> Option<TextBlock>
pub fn block_by_id(&self, block_id: usize) -> Option<TextBlock>
Get a read-only handle to a block by its entity ID.
Entity IDs are stable across insertions and deletions.
Returns None if no block with this ID exists.
Sourcepub fn snapshot_block_at_position(
&self,
position: usize,
) -> Option<BlockSnapshot>
pub fn snapshot_block_at_position( &self, position: usize, ) -> Option<BlockSnapshot>
Build a single BlockSnapshot for the block at the given position.
This is O(k) where k = format runs + image anchors in that block,
compared to snapshot_flow() which is O(n) over the entire document.
Use for incremental layout updates after single-block edits.
Sourcepub fn snapshot_block_at_position_without_highlights(
&self,
position: usize,
) -> Option<BlockSnapshot>
pub fn snapshot_block_at_position_without_highlights( &self, position: usize, ) -> Option<BlockSnapshot>
Like snapshot_block_at_position
but with no highlights applied — base fragments and empty
paint_highlights, regardless of the active sessions. Used by the
incremental relayout path of a view that has opted out of highlights.
Sourcepub fn snapshot_block_at_position_masked(
&self,
position: usize,
mask: &HighlightMask,
) -> Option<BlockSnapshot>
pub fn snapshot_block_at_position_masked( &self, position: usize, mask: &HighlightMask, ) -> Option<BlockSnapshot>
Like snapshot_block_at_position but rendering
only the sessions mask admits — the per-view incremental path (two panes over one
document can carry different find sessions). all() = the plain method; none() = the
without-highlights method.
Sourcepub fn block_at_position(&self, position: usize) -> Option<TextBlock>
pub fn block_at_position(&self, position: usize) -> Option<TextBlock>
Get a read-only handle to the block containing the given
character position. Returns None if position is out of range.
Sourcepub fn block_by_number(&self, block_number: usize) -> Option<TextBlock>
pub fn block_by_number(&self, block_number: usize) -> Option<TextBlock>
Get a read-only handle to a block by its 0-indexed global block number.
O(n): requires scanning all blocks sorted by
document_position to find the nth one. Prefer
block_at_position() or
block_by_id() in
performance-sensitive paths.
Sourcepub fn blocks(&self) -> Vec<TextBlock>
pub fn blocks(&self) -> Vec<TextBlock>
All blocks in the document, sorted by document_position. O(n).
Returns blocks from all frames, including those inside table cells.
This is the efficient way to iterate all blocks — avoids the O(n^2)
cost of calling block_by_number(i) in a loop.
Sourcepub fn blocks_in_range(&self, position: usize, length: usize) -> Vec<TextBlock>
pub fn blocks_in_range(&self, position: usize, length: usize) -> Vec<TextBlock>
All blocks whose character range intersects [position, position + length).
O(n): scans all blocks once. Returns them sorted by document_position.
A block intersects if its range [block.position, block.position + block.length)
overlaps the query range. An empty query range (length == 0) returns the
block containing that position, if any.
Sourcepub fn snapshot_flow(&self) -> FlowSnapshot
pub fn snapshot_flow(&self) -> FlowSnapshot
Snapshot the entire main flow in a single lock acquisition.
Returns a FlowSnapshot containing snapshots
for every element in the flow.
Sourcepub fn snapshot_flow_without_highlights(&self) -> FlowSnapshot
pub fn snapshot_flow_without_highlights(&self) -> FlowSnapshot
Snapshot the entire main flow with no highlights applied — base
fragments and empty paint_highlights on every block, regardless of
the active sessions.
This is the per-view opt-out: a read-only viewer that should stay
free of search / spell / syntax highlighting pulls this snapshot
instead of snapshot_flow. Because suppression
happens at build time, it works for metric-affecting sessions too
(whose highlights are otherwise merged into fragments irreversibly).
Sourcepub fn snapshot_flow_masked(&self, mask: &HighlightMask) -> FlowSnapshot
pub fn snapshot_flow_masked(&self, mask: &HighlightMask) -> FlowSnapshot
Snapshot the entire main flow rendering only the sessions mask admits.
The generalization of the plain / without-highlights pair: all() shows every session,
none() shows none, and only([...]) shows a chosen set — which is how two panes over
one shared document carry different find sessions. The effective
HighlighterKind is resolved once here, at the snapshot root,
and threaded down, so a view showing only paint-only sessions never pays the reshape
path for a metric session it does not show.
Sourcepub fn snapshot_flow_masked_no_paint(
&self,
mask: &HighlightMask,
) -> FlowSnapshot
pub fn snapshot_flow_masked_no_paint( &self, mask: &HighlightMask, ) -> FlowSnapshot
Snapshot the main flow like snapshot_flow_masked,
but without computing the paint-only overlay (paint_highlights is
empty on every block). Fragments are identical — metric sessions still
split them — so a consumer that reads only the fragments and their
geometry gets the exact same tree, minus the extract_paint_spans work.
This is the accessibility path’s snapshot: the AT tree reads fragments,
never the paint overlay, so paying to compute a per-block paint span for
each of a spell-checker’s tens of thousands of ranges is pure waste (it
dominated the a11y rebuild on a large mis-dictionaried document). Render
and layout keep using snapshot_flow_masked,
which they must — they draw the overlay.
Sourcepub fn find(
&self,
query: &str,
from: usize,
options: &FindOptions,
) -> Result<Option<FindMatch>>
pub fn find( &self, query: &str, from: usize, options: &FindOptions, ) -> Result<Option<FindMatch>>
Find the next (or previous) occurrence. Returns None if not found.
Sourcepub fn find_all(
&self,
query: &str,
options: &FindOptions,
) -> Result<Vec<FindMatch>>
pub fn find_all( &self, query: &str, options: &FindOptions, ) -> Result<Vec<FindMatch>>
Find all occurrences.
Sourcepub fn replace_text(
&self,
query: &str,
replacement: &str,
replace_all: bool,
options: &ReplaceOptions,
) -> Result<usize>
pub fn replace_text( &self, query: &str, replacement: &str, replace_all: bool, options: &ReplaceOptions, ) -> Result<usize>
Replace occurrences. Returns the number of replacements. Undoable.
options carries both how to find the text and — via
crate::ReplaceOptions::format_policy — what the replacement wears where it
overwrites formatted prose. The default drops the formatting under the replaced
range, which is fine for plain text and destructive for a rename that lands on a
partly-bold name; pass a different policy when that matters.
Sourcepub fn replace_ranges(
&self,
ranges: &[ReplaceRange],
options: &ReplaceOptions,
) -> Result<usize>
pub fn replace_ranges( &self, ranges: &[ReplaceRange], options: &ReplaceOptions, ) -> Result<usize>
Replace an explicit set of ranges, each with its own replacement text. Undoable as one action, however many ranges it touches.
replace_text can only put the same string at every match.
This is for the case where the caller decides per occurrence — a reviewed bulk
rename where some occurrences are unticked, or one that preserves the case it found
(AURÉLIEN → AURÉLIAN, not aurélian).
⚠ Do not build the ranges with a separate find_all call. The document can move
between the two, and the ranges then address text that is no longer there — which
does not fail, it rewrites the wrong words. Use
find_and_replace, which does both under one lock.
Ranges that straddle a block boundary, or that overlap one another, are skipped; the returned count reflects only what was actually applied.
Sourcepub fn find_and_replace(
&self,
query: &str,
options: &ReplaceOptions,
decide: impl FnMut(&str, usize) -> Option<String>,
) -> Result<usize>
pub fn find_and_replace( &self, query: &str, options: &ReplaceOptions, decide: impl FnMut(&str, usize) -> Option<String>, ) -> Result<usize>
Find every match of query and let decide choose what each becomes — atomically.
decide is handed the matched text and the index of the match, and returns the
replacement, or None to leave that occurrence alone. So a rename that preserves case
and skips the occurrences a writer unticked is one call:
doc.find_and_replace("Aurélien", &ReplaceOptions::new(FindOptions::default()), |matched, i| {
if excluded.contains(&i) {
return None; // the writer unticked this one
}
Some(if matched.chars().all(char::is_uppercase) { "AURÉLIAN".into() } else { "Aurélian".into() })
})?;The scan and the splice happen under one lock, which is the whole point. Calling
find_all and then replace_ranges would drop the lock in between, and the document
can be edited there — after which every range addresses text that has moved. That does
not raise an error; it silently rewrites the wrong words. The document mutex is not
reentrant, so composing the two public methods cannot close the gap; only doing both
inside one can.
Sourcepub fn add_resource(
&self,
resource_type: ResourceType,
name: &str,
mime_type: &str,
data: &[u8],
) -> Result<()>
pub fn add_resource( &self, resource_type: ResourceType, name: &str, mime_type: &str, data: &[u8], ) -> Result<()>
Add a resource (image, stylesheet) to the document.
Sourcepub fn resource(&self, name: &str) -> Result<Option<Vec<u8>>>
pub fn resource(&self, name: &str) -> Result<Option<Vec<u8>>>
Get a resource by name. Returns None if not found.
Uses an internal cache to avoid scanning all resources on repeated lookups.
Sourcepub fn clear_undo_redo(&self)
pub fn clear_undo_redo(&self)
Clear all undo/redo history.
Sourcepub fn is_modified(&self) -> bool
pub fn is_modified(&self) -> bool
Returns true if the document has been modified since creation or last reset.
Sourcepub fn set_modified(&self, modified: bool)
pub fn set_modified(&self, modified: bool)
Set or clear the modified flag.
Sourcepub fn text_direction(&self) -> TextDirection
pub fn text_direction(&self) -> TextDirection
Get the text direction.
Sourcepub fn set_text_direction(&self, direction: TextDirection) -> Result<()>
pub fn set_text_direction(&self, direction: TextDirection) -> Result<()>
Set the text direction.
Sourcepub fn default_wrap_mode(&self) -> WrapMode
pub fn default_wrap_mode(&self) -> WrapMode
Get the default wrap mode.
Sourcepub fn set_default_wrap_mode(&self, mode: WrapMode) -> Result<()>
pub fn set_default_wrap_mode(&self, mode: WrapMode) -> Result<()>
Set the default wrap mode.
Sourcepub fn default_language(&self) -> String
pub fn default_language(&self) -> String
Get the document-wide default language (ISO 639-1 code, e.g. “en”).
This is the fallback hyphenation language for blocks that don’t set
their own language. Defaults to "en" when never set.
Sourcepub fn set_default_language(&self, language: &str) -> Result<()>
pub fn set_default_language(&self, language: &str) -> Result<()>
Set the document-wide default language (ISO 639-1 code). Blocks
without an explicit language inherit this for hyphenation.
Sourcepub fn on_change<F>(&self, callback: F) -> Subscription
pub fn on_change<F>(&self, callback: F) -> Subscription
Subscribe to document events via callback.
Callbacks are invoked outside the document lock (after the editing
operation completes and the lock is released). It is safe to call
TextDocument or TextCursor methods from within the callback without
risk of deadlock. However, keep callbacks lightweight — they run
synchronously on the calling thread and block the caller until they
return.
Drop the returned Subscription to unsubscribe.
§Breaking change (v0.0.6)
The callback bound changed from Send to Send + Sync in v0.0.6
to support Arc-based dispatch. Callbacks that capture non-Sync
types (e.g., Rc<T>, Cell<T>) must be wrapped in a Mutex.
Sourcepub fn poll_events(&self) -> Vec<DocumentEvent>
pub fn poll_events(&self) -> Vec<DocumentEvent>
Return events accumulated since the last poll_events() call.
This delivery path is independent of callback dispatch via
on_change — using both simultaneously is safe
and each path sees every event exactly once.
Sourcepub fn set_syntax_highlighter(
&self,
highlighter: Option<Arc<dyn SyntaxHighlighter>>,
)
pub fn set_syntax_highlighter( &self, highlighter: Option<Arc<dyn SyntaxHighlighter>>, )
Attach a single syntax highlighter to this document — the classic, one-highlighter entry point.
Immediately re-highlights the entire document. Replaces the one highlighter this
method manages, and only that one: a spell-checker or find layer registered
independently via add_syntax_session /
add_range_session is left untouched. Pass None to remove
it.
This is a convenience over the session registry — it owns exactly one “shim” session. A host that wants to manage several layers uses the session methods directly.
Sourcepub fn add_syntax_session(
&self,
highlighter: Arc<dyn SyntaxHighlighter>,
) -> SessionId
pub fn add_syntax_session( &self, highlighter: Arc<dyn SyntaxHighlighter>, ) -> SessionId
Register a syntax session — a SyntaxHighlighter
callback with its own per-block state cascade — and return its crate::SessionId.
Unlike set_syntax_highlighter, this adds rather
than replaces: a document can carry a syntax highlighter and a spell-checker at once,
each a session, merged in registration order (a later session’s field wins). Sessions
remain visible only in views whose HighlightMask
admits them.
Sourcepub fn add_range_session(&self) -> SessionId
pub fn add_range_session(&self) -> SessionId
Register an empty range session — absolute-offset ranges set with
set_session_ranges, the shape used for search and (later)
an externally-driven spell-checker. Returns its crate::SessionId.
A view’s own find session is a range session it alone admits; that is how two panes over one document highlight different queries.
Sourcepub fn set_session_ranges(
&self,
id: SessionId,
ranges: Vec<RangeHighlight>,
) -> bool
pub fn set_session_ranges( &self, id: SessionId, ranges: Vec<RangeHighlight>, ) -> bool
Replace the ranges of a range session (absolute char offsets, the space
FindMatch reports in). Returns false if id is not a range
session.
Fires a highlight-changed event so live views showing this session re-snapshot — the only signal there is, since the ranges do not mutate the document.
Sourcepub fn remove_session(&self, id: SessionId) -> bool
pub fn remove_session(&self, id: SessionId) -> bool
Retire a session (of either kind). Returns whether it existed.
Sourcepub fn rehighlight(&self)
pub fn rehighlight(&self)
Re-highlight the entire document.
Call this when the highlighter’s rules change (e.g., new keywords were added, spellcheck dictionary updated).
Sourcepub fn rehighlight_block(&self, block_id: usize)
pub fn rehighlight_block(&self, block_id: usize)
Re-highlight a single block and cascade to subsequent blocks if the block state changes.
Source§impl TextDocument
impl TextDocument
Sourcepub fn append_line(&self, text: &str) -> Result<usize>
pub fn append_line(&self, text: &str) -> Result<usize>
Append text as a new block at the end, returning the document’s new
block count.
The append half of a streaming buffer. Costs the rope insert and one
entity write, whatever the buffer already holds — against ~15.9 ms per
line at 10 000 lines through the ordinary editing path
(docs/streaming-baseline.md).
The returned count is what a scrollback cap is checked against, so a
caller never needs a separate count call — which matters, because
block_count walks the whole document:
let count = doc.append_line(line)?;
if count > CAP {
doc.truncate_front(count - CAP)?;
}text is taken as a single line: it must not contain \n, since a block
is one line by construction here (embedded newlines would desynchronize
the rope from the block index). Returns DocumentError::InvalidArgument
if it does.
Not undoable, by design — see the module docs.
Sourcepub fn append_lines<I, S>(&self, lines: I) -> Result<usize>
pub fn append_lines<I, S>(&self, lines: I) -> Result<usize>
Append several lines in one go, returning the document’s new block count.
Equivalent to append_line per line, but pays the
document-count write and the throwaway-stack clear once for the batch
rather than per line. A view draining a channel once per frame should
prefer this.
No line may contain \n.
Not undoable, by design — see the module docs.
Sourcepub fn truncate_front(&self, n: usize) -> Result<usize>
pub fn truncate_front(&self, n: usize) -> Result<usize>
Drop the first n blocks, returning how many were actually removed.
The eviction half of a streaming buffer. Returns less than n when the
document holds fewer blocks; a document is never emptied completely —
one block always remains, since an empty document is not a valid state
here (it is created with one block, and the rest of the API assumes at
least one exists).
Not undoable, by design — see the module docs.
Trait Implementations§
Source§impl Clone for TextDocument
impl Clone for TextDocument
Source§fn clone(&self) -> TextDocument
fn clone(&self) -> TextDocument
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more