pub struct IncrementalDocument { /* private fields */ }Expand description
A document that rescans only what an edit disturbed.
This is the path an editor takes, where a full scan on every keystroke would be wasted work. The document keeps the previous revision’s report and its restart points, and an edit is answered by scanning from the last safe point before it up to the first point where the new scan converges with the old one; everything outside that window is reused, with the spans past the edit shifted by its length delta.
The result is byte-for-byte the report scan would have
produced for the same bytes — a restart point is only used while the
bytes around it still permit one, and a scan that fails to converge
simply runs to the end. Self::last_rescan_span says how much of the
document the last edit actually cost.
§Examples
use ocomment_core::{
ByteSpan, DocumentChange, IncrementalDocument, IncrementalError, Language, ScanOptions,
};
let mut document = IncrementalDocument::new(
b"let x = 1; // note\nlet y = 2;\n".to_vec(),
Language::Rust,
ScanOptions::default(),
1,
);
assert_eq!(document.report().comments.len(), 1);
// Type a second comment onto the end of the second line.
let end = document.source().len() - 1;
let report = document
.apply_changes(
&[DocumentChange {
span: ByteSpan::new(end, end),
replacement: b" // more".to_vec(),
}],
2,
)
.unwrap();
assert_eq!(report.comments.len(), 2);
// A batch that fails validation changes nothing, the version included.
assert_eq!(
document.apply_changes(&[], 2),
Err(IncrementalError::StaleVersion {
received: 2,
current: 2,
}),
);
assert_eq!(document.version(), 2);
assert_eq!(document.report().comments.len(), 2);Implementations§
Source§impl IncrementalDocument
impl IncrementalDocument
Sourcepub fn new(
source: Vec<u8>,
language: Language,
options: ScanOptions,
version: i64,
) -> Self
pub fn new( source: Vec<u8>, language: Language, options: ScanOptions, version: i64, ) -> Self
Scan source once and hold on to what it takes to rescan cheaply.
version is the client’s revision number for these bytes; every later
Self::apply_changes has to advance on it.
Sourcepub fn report(&self) -> &ScanReport
pub fn report(&self) -> &ScanReport
The scan of the current bytes.
Sourcepub const fn language(&self) -> Language
pub const fn language(&self) -> Language
The language the document is scanned as, fixed when it was created.
Sourcepub fn scan_options(&self) -> &ScanOptions
pub fn scan_options(&self) -> &ScanOptions
The options the document is scanned under, fixed when it was created.
Sourcepub fn transform(&self, layout: Layout) -> TransformResult
pub fn transform(&self, layout: Layout) -> TransformResult
The bytes a removal would write, from the report already in hand.
No comment is scanned again: this is the current report run through the
same layout and source-map engine transform uses.
A YAML document does get one extra lexical pass in there, because where
a block scalar body ends decides which comment lines a removal has to
take whole and no report carries that; it is linear, like the edit walk
beside it, and every other language skips it on the language check.
Sourcepub const fn last_rescan_span(&self) -> ByteSpan
pub const fn last_rescan_span(&self) -> ByteSpan
The stretch of the current bytes the last edit had to rescan.
A fresh document reports the whole source. An edit that reused both ends reports only the window between them, which is what makes the saving measurable rather than assumed.
Sourcepub fn checkpoints(&self) -> &[usize]
pub fn checkpoints(&self) -> &[usize]
The byte offset each line starts at, 0 first.
A CRLF pair counts as one terminator, so checkpoints()[n] is where
line n begins for Self::byte_offset.
Sourcepub fn safe_checkpoints(&self) -> &[usize]
pub fn safe_checkpoints(&self) -> &[usize]
The offsets a rescan may restart from and still reproduce a full scan.
Far fewer than Self::checkpoints: a line start only qualifies while
the scanner is in a clean top-level state there and the bytes around it
keep it that way.
Sourcepub fn apply_changes(
&mut self,
changes: &[DocumentChange],
version: i64,
) -> Result<&ScanReport, IncrementalError>
pub fn apply_changes( &mut self, changes: &[DocumentChange], version: i64, ) -> Result<&ScanReport, IncrementalError>
Apply a sorted, non-overlapping batch whose spans refer to the current document snapshot. Validation is transactional: an invalid batch does not alter the source, report, checkpoints, or version.
An empty batch is accepted and only advances the version, which is what a client that saved without typing sends.
§Errors
IncrementalError::StaleVersion when version does not advance on
the current one, and IncrementalError::InvalidSpan when a change is
inverted, starts before its predecessor ends, or reaches past the end
of the document. Both are raised before anything is written.
§Examples
See IncrementalDocument for a worked edit.
Sourcepub fn byte_offset(
&self,
line: u32,
character: u32,
encoding: PositionEncoding,
) -> Result<usize, IncrementalError>
pub fn byte_offset( &self, line: u32, character: u32, encoding: PositionEncoding, ) -> Result<usize, IncrementalError>
The byte offset of a line-and-character position.
line is zero-based, and character is a zero-based offset into that
line counted in the units encoding names. The end of a line is a
valid position; the terminator itself is not part of the line.
§Errors
IncrementalError::InvalidPosition when the line does not exist,
when character reaches past the end of the line, or when it lands
inside a character instead of on a boundary. A line whose bytes are
not valid UTF-8 has no UTF-16 or UTF-32 positions at all.
Trait Implementations§
Source§impl Clone for IncrementalDocument
impl Clone for IncrementalDocument
Source§fn clone(&self) -> IncrementalDocument
fn clone(&self) -> IncrementalDocument
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more