Buffer

Struct Buffer 

Source
pub struct Buffer {
    pub current: Snapshot,
    /* private fields */
}
Expand description

Long-lived state of the editor’s text buffer. Factored into sub-structs for borrow-checking.

§Operation algebra

Operations are created based on a version of the buffer. This version is called the operation’s base and is identified with a sequence number. When the base of an operation is equal to the buffer’s current sequence number, the operation can be applied and increments the buffer’s sequence number.

When multiple operations are created based on the same version of the buffer, such as when a user types a few keystrokes in one frame or issues a command like indenting multiple list items, the operations all have the same base. Once the first operation is applied and the buffer’s sequence number is incremented, the base of the remaining operations must be incremented by using the first operation to transform them before they can be applied. This corresponds to the reality that the buffer state has changed since the operation was created and the operation must be re-interpreted. For example, if text is typed at the beginning then end of a buffer in one frame, the position of the text typed at the end of the buffer is greater when it is applied than it was when it was typed.

External changes are merged into the buffer by creating a set of operations that would transform the buffer from the last external state to the current state. These operations, based on the version of the buffer at the last successful save or load, must be transformed by all operations that have been applied since (this means we must preserve the undo history for at least that long; if this presents performance issues, we can always save). Each operation that is transforming the new operations will match the base of the new operations at the time of transformation. Finally, the operations will need to transform each other just like any other set of operations made in a single frame/made based on the same version of the buffer.

§Undo (work in progress)

Undo should revert local changes only, leaving external changes in-tact, so that when all local changes are undone, the buffer is in a state reflecting external changes only. This is complicated by the fact that external changes may have been based on local changes that were synced to another client. To undo an operation that had an external change based on it, we have to interpret the external change in the absence of local changes that were present when it was created. This is the opposite of interpreting the external change in the presence of local changes that were not present when it was created i.e. the normal flow of merging external changes. Here, we are removing a local operation from the middle of the chain of operations that led to the current state of the buffer.

To do this, we perform the dance of transforming operations in reverse, taking a chain of operations each based on the prior and transforming them into a set of operations based on the same base as the operation to be undone. Then we remove the operation to be undone and apply the remaining operations with the forward transformation flow.

Operations are not invertible i.e. you cannot construct an inverse operation that will perfectly cancel out the effect of another operation regardless of the time of interpretation. For example, with a text replacement, you can construct an inverse text replacement that replaces the new range with the original text, but when operations are undone from the middle of the chain, it may affect the original text. The operation will be re-interpreted based on a new state of the buffer at its time of application. The replaced text has no fixed value by design.

However, it is possible to undo the specific application of an operation in the context of the state of the buffer when it was applied. We store information necessary to undo applied operations alongside the operations themselves i.e. the text replaced in the application. When the operation is transformed for any reason, this undo information is invalidated.

Fields§

§current: Snapshot

Current contents of the buffer (what should be displayed in the editor). Todo: hide behind a read-only accessor

Implementations§

Source§

impl Buffer

Source

pub fn queue(&mut self, ops: Vec<Operation>)

Push a series of operations onto the buffer’s input queue; operations will be undone/redone atomically. Useful for batches of internal operations produced from a single input event e.g. multi-line list identation.

Source

pub fn reload(&mut self, text: String)

Loads a new string into the buffer, merging out-of-editor changes made since last load with in-editor changes made since last load. The buffer’s undo history is preserved; undo’ing will revert in-editor changes only. Exercising undo’s may put the buffer in never-before-seen states and exercising all undo’s will revert the buffer to the most recently loaded state (undo limit permitting). Note: undo behavior described here is aspirational and not yet implemented.

Source

pub fn saved(&mut self, external_seq: usize, external_text: String)

Indicates to the buffer the changes that have been saved outside the editor. This will serve as the new base for merging external changes. The sequence number should be taken from current.seq of the buffer when the buffer’s contents are read for saving.

Source

pub fn merge(self, external_text_a: String, external_text_b: String) -> String

Source

pub fn update(&mut self) -> Response

Applies all operations in the buffer’s input queue

Source

pub fn can_redo(&self) -> bool

Source

pub fn can_undo(&self) -> bool

Source

pub fn redo(&mut self) -> Response

Source

pub fn undo(&mut self) -> Response

Source

pub fn is_empty(&self) -> bool

Reports whether the buffer’s current text is empty.

Source

pub fn selection_text(&self) -> String

Trait Implementations§

Source§

impl Default for Buffer

Source§

fn default() -> Buffer

Returns the “default value” for a type. Read more
Source§

impl From<&str> for Buffer

Source§

fn from(value: &str) -> Self

Converts to this type from the input type.
Source§

impl Index<(DocByteOffset, DocByteOffset)> for Buffer

Source§

type Output = str

The returned type after indexing.
Source§

fn index(&self, index: (DocByteOffset, DocByteOffset)) -> &Self::Output

Performs the indexing (container[index]) operation. Read more
Source§

impl Index<(DocCharOffset, DocCharOffset)> for Buffer

Source§

type Output = str

The returned type after indexing.
Source§

fn index(&self, index: (DocCharOffset, DocCharOffset)) -> &Self::Output

Performs the indexing (container[index]) operation. Read more

Auto Trait Implementations§

§

impl Freeze for Buffer

§

impl RefUnwindSafe for Buffer

§

impl Send for Buffer

§

impl Sync for Buffer

§

impl Unpin for Buffer

§

impl UnwindSafe for Buffer

Blanket Implementations§

§

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

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

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

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

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

§

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

Mutably borrows from an owned value. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Converts Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Converts &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Converts &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSend for T
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_sync(self: Box<T>) -> Box<dyn Any + Sync + Send>

Converts Box<Trait> (where Trait: DowncastSync) to Box<dyn Any + Send + Sync>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Converts Arc<Trait> (where Trait: DowncastSync) to Arc<Any>, which can then be downcast into Arc<ConcreteType> where ConcreteType implements Trait.
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
§

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

§

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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
§

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

§

type Error = Infallible

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

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

Performs the conversion.
§

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

§

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

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

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

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> Fruit for T
where T: Send + Downcast,