Skip to main content

IncrementalDocument

Struct IncrementalDocument 

Source
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

Source

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.

Source

pub fn source(&self) -> &[u8]

The current bytes of the document.

Source

pub fn report(&self) -> &ScanReport

The scan of the current bytes.

Source

pub const fn language(&self) -> Language

The language the document is scanned as, fixed when it was created.

Source

pub fn scan_options(&self) -> &ScanOptions

The options the document is scanned under, fixed when it was created.

Source

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.

Source

pub const fn version(&self) -> i64

The revision number of the current bytes.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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

Source§

fn clone(&self) -> IncrementalDocument

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for IncrementalDocument

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.