Implements an efficient buffer for text editing.
{ head : Array a
, zip : Maybe { val : b
, at : Basics.Int
, tail : Array a }
, length : Basics.Int
, toFocus : a -> b
, fromFocus : Maybe a -> b -> a
}
A GapBuffer model.
empty : (a -> b) -> (Maybe a -> b -> a) -> GapBuffer a b
Creates an empty GapBuffer
.
fromArray : (a -> b) -> (Maybe a -> b -> a) -> Array a -> GapBuffer a b
Creates a GapBuffer
from an Array
.
fromList : (a -> b) -> (Maybe a -> b -> a) -> List a -> GapBuffer a b
Creates a GapBuffer
from a List
.
get : Basics.Int -> GapBuffer a b -> Maybe a
Extracts the element at the specified index in the GapBuffer
.
If the GapBuffer
does not hold data for this index, Nothing
is returned.
isEmpty : GapBuffer a b -> Basics.Bool
Checks if a GapBuffer
is empty.
length : GapBuffer a b -> Basics.Int
Gets the number of element in the GapBuffer
.
slice : Basics.Int -> Basics.Int -> GapBuffer a b -> Array a
Extracts a slice of data from the buffer, between the from and to indices specified.
If these indicies go outside the range of the GapBuffer
, data from the
actual available range will be returned.
If you are iterating over the contents of the buffer, to render a
UI for example, there is no need to copy the contents into an intermediate
Array
. You can iterate directly over a region of the buffer using the
foldlSlice
function instead.
currentFocus : GapBuffer a b -> Maybe ( Basics.Int, b )
If the buffer has a current focus point, its position and the data element at it are returned.
getFocus : Basics.Int -> GapBuffer a b -> ( GapBuffer a b, Maybe b )
Gets the value at the specified focus of the GapBuffer
. If the GapBuffer
was
already focussed at a different index, that index will be de-focussed, and the
focus shifted to the specified index.
Note that de-focussing and re-focussing the GapBuffer
will use the toFocus
and
fromFocus
functions that were specified when creating the buffer.
setFocus : Basics.Int -> b -> GapBuffer a b -> GapBuffer a b
Sets the value as the focus of the GapBuffer
.
If the GapBuffer
was already focussed at a different index, that index will be
de-focussed, and the focus shifted to the specified index.
Note that de-focussing and re-focussing the GapBuffer
will use the toFocus
and
fromFocus
functions that were specified when creating the buffer.
insertAtFocus : Basics.Int -> b -> GapBuffer a b -> GapBuffer a b
Inserts an entry at the specified index into the buffer.If the GapBuffer was already focussed at a different index, that index will be de-focussed, and the focus shifted to the specified index. Entries at higher indexes will now have an index one higher than before.
Note that de-focussing and re-focussing the GapBuffer will use the toFocus and fromFocus functions that were specified when creating the buffer.
If the index is out of range for the buffer this operation will do nothing.
updateFocus : Basics.Int -> (b -> b) -> GapBuffer a b -> GapBuffer a b
Update the value at the specified focus of the GapBuffer
. If the GapBuffer
was
already focussed at a different index, that index will be de-focussed, and the
focus shifted to the specified index.
Note that de-focussing and re-focussing the GapBuffer
will use the toFocus
and
fromFocus
functions that were specified when creating the buffer.
focusAt : Basics.Int -> GapBuffer a b -> GapBuffer a b
Focusses the buffer at the specified index. If the GapBuffer was already focussed at a different index, that index will be de-focussed, and the focus shifted to the specified index.
Note that de-focussing and re-focussing the GapBuffer will use the toFocus and fromFocus functions that were specified when creating the buffer.
If the index is out of range for the buffer this operation clamp the index to the available range. Negative values will set the focus to zero. Values greater than the buffer length will be off the end of the buffer, so no focus will be set.
delete : Basics.Int -> GapBuffer a b -> GapBuffer a b
Deletes the specified index from the buffer. If the GapBuffer was already focussed at a different index, that index will be de-focussed, and the focus shifted to the specified index. Entries at higher indexes will now have an index one less than before.
Note that de-focussing and re-focussing the GapBuffer will use the toFocus and fromFocus functions that were specified when creating the buffer.
If the index is out of range for the buffer this operation will do nothing.
advanceFocus : (b -> Maybe b) -> GapBuffer a b -> Maybe (GapBuffer a b)
Advances the focus by 1. If there is no focus becuase it fell off the end this returns nothing.
A function is supplied that can optionally map the entry at the current focus
into a new entry. If this mapping returns Nothing, then the focus is advanced.
If this mapping returns a value, the focus is not advanced and the new entry
replaces the one at the current focus. This feature can be used to stack
advanceFocus
functions together over GapBuffers
of GapBuffers
of ...
The possible outcomes of ripple operations.
A ripple is an operation which can complete all the way to the end of the buffer, or can be stopped when it reaches a certain point from which it can be continued.
ripple : Basics.Int -> Basics.Int -> (a -> a -> Basics.Bool) -> GapBuffer a b -> ( GapBuffer a b, RippleOutcome )
Rippling runs the buffer focus between a 'from' index and a 'to' index. Each entry encountered is extracted from the buffer and re-merged into the buffer by passing it through its 'toFocus' and 'fromFocus' functions.
This can be used to apply an operation such as formatting the text correctly, but only within a window of the buffer. For example, in an editor working on 1 million lines, a change on an earlier line my change the formatting on later lines, but we only want to apply the formatting on lines that the user can currently see, or the operation will be too slow.
Since we know where a ripply operation ended, it can be re-run from that point. Or ripple operations can be cancelled if they are overtaking by other ripple operations.
foldlSlice : (Basics.Int -> a -> acc -> acc) -> acc -> Basics.Int -> Basics.Int -> GapBuffer a b -> acc
Iterates forward over a region of the buffer.
This is the most efficient way to extract and map data from the buffer. For
example, you would use this when rendering the visible contents of a GapBuffer
to Html. The implementation does not create intermediate data structures to hold
the extracted elements, and it only iterates over the range you specify.
foldrSlice : (Basics.Int -> a -> acc -> acc) -> acc -> Basics.Int -> Basics.Int -> GapBuffer a b -> acc
Iterates backward over a region of the buffer.
This is the most efficient way to extract and map data from the buffer. For
example, you would use this when rendering the visible contents of a GapBuffer
to Html. The implementation does not create intermediate data structures to hold
the extracted elements, and it only iterates over the range you specify.
indexedFoldl : (Basics.Int -> a -> acc -> acc) -> acc -> GapBuffer a b -> acc
Iterates forward over the whole buffer.
This is the most efficient way to extract and map data from the buffer. For
example, you would use this when rendering the visible contents of a GapBuffer
to Html. The implementation does not create intermediate data structures to hold
the extracted elements, and it only iterates over the range you specify.
indexedFoldr : (Basics.Int -> a -> acc -> acc) -> acc -> GapBuffer a b -> acc
Iterates backward over the whole buffer.
This is the most efficient way to extract and map data from the buffer. For
example, you would use this when rendering the visible contents of a GapBuffer
to Html. The implementation does not create intermediate data structures to hold
the extracted elements, and it only iterates over the range you specify.