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 to_plain_text_indented(&self) -> Result<String>
pub fn to_plain_text_indented(&self) -> Result<String>
to_plain_text for writing an actual .txt file: quoted
blocks are indented four spaces per blockquote level, so an epigraph or a block
quotation still reads as set-off matter in a format with no markup to say so.
Not interchangeable with to_plain_text, and not cached.
That one is pinned character-for-character to the document’s addressable text — the
text find_all and replace_text compute
offsets against — so indenting it would shift every offset inside a quote and
desynchronise search from the document. Use this only for output nobody addresses
back into the document.
Sourcepub fn to_plain_text_with(
&self,
options: PlainTextExportOptions,
) -> Result<String>
pub fn to_plain_text_with( &self, options: PlainTextExportOptions, ) -> Result<String>
to_plain_text with every presentation option chosen
explicitly — quoted-block indentation, and a U+000C form feed before each block
that asks to start a new page.
Subject to the same warning as to_plain_text_indented:
anything other than PlainTextExportOptions::addressable shifts offsets, so this is
for files being written out, never for text anyone addresses back into the document.
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 to_markdown_with(&self, options: MarkdownExportOptions) -> Result<String>
pub fn to_markdown_with(&self, options: MarkdownExportOptions) -> Result<String>
to_markdown with the presentation opt-ins — today, whether a
block that asks to start a new page gets a raw-HTML page break emitted above it.
Off by default, because raw HTML is not 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_html(&self) -> Result<String>
pub fn to_html(&self) -> Result<String>
Export the entire document as HTML.
Inline images keep whatever src the document stores; placing the files
those point at is the caller’s business. Use
to_html_with_options to inline them
instead, or to drop them.
Sourcepub fn to_html_with_options(&self, options: HtmlExportOptions) -> Result<String>
pub fn to_html_with_options(&self, options: HtmlExportOptions) -> Result<String>
Export as HTML, choosing how inline images are represented.
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.
Images are emitted as \includegraphics{src}, which LaTeX resolves
against the filesystem at compile time — so the caller is responsible for
placing those files beside the .tex. Use
to_latex_with_options to drop them
instead.
Sourcepub fn to_latex_with_options(
&self,
document_class: &str,
include_preamble: bool,
omit_images: bool,
) -> Result<String>
pub fn to_latex_with_options( &self, document_class: &str, include_preamble: bool, omit_images: bool, ) -> Result<String>
to_latex, with the choice of dropping inline images.
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 set_footnote_markers(&self, markers: HashMap<String, String>)
pub fn set_footnote_markers(&self, markers: HashMap<String, String>)
Tell the document what each footnote label should print.
Presentation only: never stored, never exported, never part of the text. A reference occupies one character whatever its marker says.
Set it when the numbers are a fact about something larger than this document — a host compiling one chapter of a book knows the chapter’s notes continue a sequence this document cannot see. Leave it unset and the document numbers its own references in reading order, which is right when the document is the whole text. Storing the map is only half of it: a marker is shaped text, so a document already laid out keeps drawing the old one until something tells it to reshape. Nothing else will — the map is presentation state and changing it edits no block, so it emits no edit event of its own. Without the notification below, a host that numbers a note the instant it is created watches the raw label sit in the writer’s prose until an unrelated keystroke happens to force a relayout.
FormatChanged over the whole document rather than a paint-only event:
the marker’s width changes with its text (9 and 10 are not the same
size), so the line has to be reshaped, not recoloured. Guarded on the map
actually differing, because a host pushes this on every refresh and a
full relayout per keystroke is not a thing to do by accident.
Sourcepub fn footnote_references(&self) -> Vec<(usize, String)>
pub fn footnote_references(&self) -> Vec<(usize, String)>
Every footnote reference in the document, as (position, label), in
reading order.
The seam a host uses to tie its own note storage to the prose: Skribisto keeps note bodies in its store, so what it needs from the document is only where the references are and which note each names.
Positions are document-absolute character offsets — the same space a cursor and a search hit use — so a caller can go straight from a caret to the note under it without a second lookup.
Sourcepub fn footnote_reference_at(&self, position: usize) -> Option<String>
pub fn footnote_reference_at(&self, position: usize) -> Option<String>
The label of the footnote reference at position, if one sits there.
What “the caret is on a footnote” means, for a host wiring a two-way selection between its notes list and the prose.
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 sentence_at(
&self,
position: usize,
content_locale: Option<&str>,
) -> Option<(usize, usize)>
pub fn sentence_at( &self, position: usize, content_locale: Option<&str>, ) -> Option<(usize, usize)>
The sentence containing position, as absolute char offsets (start, end) — the
granularity between word and block_at.
content_locale is a BCP-47-ish tag ("en", "en-US", "pt_BR") naming the language
the text is written in. It selects the sentence tailoring for that language —
abbreviations that do not end a sentence, French spaced guillemets, the Greek question
mark. Pass it fresh on every call, like FindOptions::language:
only the caller knows what language the text is in, and it is not document state.
None, or a language with no tailoring, falls back to plain UAX #29.
A sentence never crosses a block: a paragraph break always ends one. Returns None when
the block holds no sentence to point at (empty, or whitespace only). Trailing whitespace
is trimmed off the end, so the range covers the sentence and not the gap after it.
The trailing edge is inclusive of the caret: a position at the very end of the block
resolves to the last sentence rather than to nothing.
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 content_revision(&self) -> u64
pub fn content_revision(&self) -> u64
A monotonic counter, bumped once per DocumentEvent::ContentsChanged
queued so far. Starts at 0.
Lets a caller answer “was this notification caused by exactly the
most recent edit, with nothing else having happened since” precisely
— snapshot the value when acting on a notification, and compare it
against the current value later. This is deliberately not the same
as is_modified (a flag, not a count) or the
undo stack’s depth (which does not grow when consecutive compatible
edits merge into one entry — e.g. fast consecutive typing).
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 (priority, registration) order (a later session’s field
wins). Sessions remain visible only in views whose
HighlightMask admits them.
Sourcepub fn add_syntax_session_with_priority(
&self,
highlighter: Arc<dyn SyntaxHighlighter>,
priority: i32,
) -> SessionId
pub fn add_syntax_session_with_priority( &self, highlighter: Arc<dyn SyntaxHighlighter>, priority: i32, ) -> SessionId
add_syntax_session at an explicit merge priority — see
add_range_session_with_priority.
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 add_range_session_with_priority(&self, priority: i32) -> SessionId
pub fn add_range_session_with_priority(&self, priority: i32) -> SessionId
add_range_session at an explicit merge priority.
Where two sessions format the same character, the higher priority wins field by field;
equal priorities fall back to registration order, which is what every session gets by
default (0).
Reach for this when a layer must reliably lose — an ambient background band that every find match and spell squiggle should paint over. Registration order cannot express that: a per-view layer is registered when its view appears, so whether it lands before or after the find session depends on the order the user happened to open things in.
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