class TextFieldBuffer
internal constructor(
initialValue: TextFieldCharSequence,
initialChanges: ChangeTracker? = null,
internal val originalValue: TextFieldCharSequence = initialValue,
private val offsetMappingCalculator: OffsetMappingCalculator? = null,
) : Appendable
A text buffer that can be edited, similar to StringBuilder.
This class provides methods for changing the text, such as:
This class also stores and tracks the cursor position or selection range. The cursor position is just a selection range with zero length. The cursor and selection can be changed using methods such as:
To get one of these, and for usage samples, see TextFieldState.edit. Every change to the buffer is tracked in a ChangeList which you can access via the changes property.
Properties
length
val length: Int
The number of characters in the text field.
originalText
val originalText: CharSequence
Original text content of the buffer before any changes were applied. Calling revertAllChanges will set the contents of this buffer to this value.
originalSelection
val originalSelection: TextRange
Original selection before the changes. Calling revertAllChanges will set the selection to this value.
changes
@ExperimentalFoundationApi
val changes: ChangeList
The ChangeList represents the changes made to this value and is inherently mutable. This means that the returned ChangeList always reflects the complete list of changes made to this value at any given time, even those made after reading this property.
hasSelection
val hasSelection: Boolean
True if the selection range has non-zero length. If this is false, then the selection represents the cursor.
selection
var selection: TextRange
The selected range of characters.
Places the selection around the given range in characters.
If the start or end of TextRange fall inside surrogate pairs or other invalid runs, the values will be adjusted to the nearest earlier and later characters, respectively.
To place the start of the selection at the beginning of the field, set this value to TextRange.Zero. To place the end of the selection at the end of the field, after the last character, pass TextFieldBuffer.length. Passing a zero-length range is the same as calling placeCursorBeforeCharAt.
textRange
var TrackedRange<*>.textRange: TextRange
The TextRange of this style. This range will reflect the up-to-date style range as the text is edited.
This property is only accessible within the TextFieldBuffer block where the TrackedRange was created. Do not keep a reference to the TrackedRange outside of that block.
Modifying the text can potentially invalidate a TrackedRange if its length collapses to zero. It is recommended to check valid before accessing this property if any text changes were made, or if the range might have been explicitly removed via removeStyle.
Setting this property will update the range of the style in-place, preserving its original applying order relative to other styles in the buffer.
spanStyle
var TrackedRange<SpanStyle>.spanStyle: SpanStyle
The SpanStyle object associated with this TrackedRange.
This property is only accessible within the TextFieldBuffer block where the TrackedRange was created.
Modifying the text can potentially invalidate a TrackedRange if its length collapses to zero. It is recommended to check valid before accessing this property if any text changes were made, or if the range might have been explicitly removed via removeStyle.
Setting this property will update the style applied to the text in-place, preserving its original applying order relative to other styles in the buffer.
paragraphStyle
var TrackedRange<ParagraphStyle>.paragraphStyle: ParagraphStyle
The ParagraphStyle object associated with this TrackedRange.
This property is only accessible within the TextFieldBuffer block where the TrackedRange was created.
Modifying the text can potentially invalidate a TrackedRange if its length collapses to zero. It is recommended to check valid before accessing this property if any text changes were made, or if the range might have been explicitly removed via removeStyle.
Setting this property will update the style applied to the text in-place, preserving its original applying order relative to other styles in the buffer.
valid
val TrackedRange<*>.valid: Boolean
Whether this TrackedRange is still valid in the buffer.
A style ceases to exist when removeStyle is called or when its range collapses to a length of zero due to text edits. Once it no longer exists, accessing or modifying its properties will throw an IllegalStateException.
This property is only accessible within the TextFieldBuffer scope where the TrackedRange was created.
expandPolicy
var TrackedRange<*>.expandPolicy: ExpandPolicy
The ExpandPolicy defining how the style range expands when text is inserted at its boundaries.
This property is only accessible within the TextFieldBuffer scope where the TrackedRange was created.
Modifying the text can potentially invalidate a TrackedRange if its length collapses to zero. It is recommended to check valid before accessing this property if any text changes were made, or if the range might have been explicitly removed via removeStyle.
Setting this property will update the expand policy in-place, preserving its original applying order relative to other styles in the buffer.
Functions
replace
fun replace(start: Int, end: Int, text: CharSequence)
Replaces the text between start (inclusive) and end (exclusive) in this value with text, and records the change in changes.
Parameters
| start | The character offset of the first character to replace. |
| end | The character offset of the first character after the text to replace. |
| text | The text to replace the range [start, end) with. |
charAt
fun charAt(index: Int): Char
Returns the Char at index in this buffer.
asCharSequence
fun asCharSequence(): CharSequence
Returns a CharSequence backed by this buffer. Any subsequent changes to this buffer will be visible in the returned sequence as well.
revertAllChanges
fun revertAllChanges()
Revert all changes made to this value since it was created.
After calling this method, this object will be in the same state it was when it was initially created, and changes will be empty.
placeCursorBeforeCharAt
fun placeCursorBeforeCharAt(index: Int)
Places the cursor before the character at the given index.
If index is inside a surrogate pair or other invalid run, the cursor will be placed at the nearest earlier index.
To place the cursor at the beginning of the field, pass index 0. To place the cursor at the end of the field, after the last character, pass index TextFieldBuffer.length or call placeCursorAtEnd.
Parameters
| index | Character index to place cursor before, should be in range 0 to TextFieldBuffer.length, inclusive. |
placeCursorAfterCharAt
fun placeCursorAfterCharAt(index: Int)
Places the cursor after the character at the given index.
If index is inside a surrogate pair or other invalid run, the cursor will be placed at the nearest later index.
To place the cursor at the end of the field, after the last character, pass index TextFieldBuffer.length or call placeCursorAtEnd.
Parameters
| index | Character index to place cursor after, should be in range 0 (inclusive) to TextFieldBuffer.length (exclusive). |
addStyle
fun addStyle(spanStyle: SpanStyle, start: Int, end: Int)
Adds the given spanStyle to the text between start and end on this buffer.
Styles are applied in the order they are added to the buffer. This order is preserved even as the text is edited and style ranges are adjusted.
Note that the same SpanStyle object can be added to multiple distinct ranges. Each call to addStyle creates a new, independent style range. This allows you to save object allocations by applying the same style object to different distinct ranges.
If ComposeFoundationFlags.isBasicTextFieldStyledTextEnabled is enabled, this function can be called from any TextFieldBuffer scope (such as InputTransformation or TextFieldState.edit). The added style will be tracked and its range will automatically adjust as the text is edited, behaving as if called with ExpandPolicy.AtEnd.
If the flag is disabled, this function is only permitted within an OutputTransformation. Any styling added in this mode will not become part of the underlying text state, nor will its boundaries be tracked or updated during subsequent edits. For predictable results when the flag is disabled, it is recommended to apply styles only after the text content has been fully determined.
addStyle
fun addStyle(paragraphStyle: ParagraphStyle, start: Int, end: Int)
Adds the given paragraphStyle to the text between start and end on this buffer.
Styles are applied in the order they are added to the buffer. This order is preserved even as the text is edited and style ranges are adjusted.
Note that the same ParagraphStyle object can be added to multiple distinct ranges. Each call to addStyle creates a new, independent style range. This allows you to save object allocations by applying the same style object to different distinct ranges.
If ComposeFoundationFlags.isBasicTextFieldStyledTextEnabled is enabled, this function can be called from any TextFieldBuffer scope (such as InputTransformation or TextFieldState.edit). The added style will be tracked and its range will automatically adjust as the text is edited, behaving as if called with ExpandPolicy.AtEnd.
If the flag is disabled, this function is only permitted within an OutputTransformation. Any styling added in this mode will not become part of the underlying text state, nor will its boundaries be tracked or updated during subsequent edits. For predictable results when the flag is disabled, it is recommended to apply styles only after the text content has been fully determined.
addStyle
fun addStyle(
spanStyle: SpanStyle,
range: TextRange,
expandPolicy: ExpandPolicy,
): TrackedRange<SpanStyle>
Adds the given spanStyle to the text within the range on this buffer.
Styles are applied in the order they are added to the buffer. This order is preserved even as the text is edited and style ranges are adjusted.
Note that the same SpanStyle object can be added to multiple distinct ranges. Each call to addStyle creates a new, independent style range, and returns a unique TrackedRange to identify it. This allows you to save object allocations by applying the same style object to different distinct ranges.
Parameters
| spanStyle | the SpanStyle to be applied |
| range | the effective range of the SpanStyle |
| expandPolicy | the ExpandPolicy defining how the style range expands when text is inserted at its boundaries. |
Returns
| a TrackedRange referencing the added style. |
addStyle
fun addStyle(
paragraphStyle: ParagraphStyle,
range: TextRange,
expandPolicy: ExpandPolicy,
): TrackedRange<ParagraphStyle>
Adds the given paragraphStyle to the text within the range on this buffer.
Styles are applied in the order they are added to the buffer. This order is preserved even as the text is edited and style ranges are adjusted.
Note that the same ParagraphStyle object can be added to multiple distinct ranges. Each call to addStyle creates a new, independent style range, and returns a unique TrackedRange to identify it. This allows you to save object allocations by applying the same style object to different distinct ranges.
Parameters
| paragraphStyle | the ParagraphStyle to be applied |
| range | the effective range of the ParagraphStyle |
| expandPolicy | the ExpandPolicy defining how the style range expands when text is inserted at its boundaries. |
Returns
| a TrackedRange referencing the added style. |
getSpanStyles
fun getSpanStyles(start: Int, end: Int): List<TrackedRange<SpanStyle>>
Returns the SpanStyles that intersect with the given range defined by start (inclusive) and end (exclusive).
Styles are returned in the same order they were originally added to the buffer.
A style intersects with the range if it overlaps with it at any point. For non-empty ranges, this means style.start < end and start < style.end.
Example Query Range: [5, 15)
0 5 10 15 20 25
|----|----|----|----|----| [---------) Query Range [5, 15)
[-------------------) Style [0, 20) (Contains query) -> Returned [----) Style [8, 12) (Inside query) -> Returned
[----------) Style [0, 10) (Overlap start) -> Returned
[----) Style [0, 5) (Touching start) -> NOT Returned [----------) Style [15, 25)(Touching end) -> NOT Returned
Example Collapsed Query: [10, 10)
0 5 10 15 20 25
|----|----|----|----|----| | Query Range [10, 10)
[-------------------) Style [0, 20) (Contains query) -> Returned
[----------) Style [0, 10) (Touching end) -> NOT Returned [----------) Style [10, 20)(Touching start) -> Returned
Parameters
| start | the inclusive start offset of the range |
| end | the exclusive end offset of the range |
Returns
| a list of TrackedRanges referencing the styles intersecting with the given range, returned in the order they were added to the buffer. |
getParagraphStyles
fun getParagraphStyles(start: Int, end: Int): List<TrackedRange<ParagraphStyle>>
Returns the ParagraphStyles that intersect with the range defined by start (inclusive) and end (exclusive).
Styles are returned in the same order they were originally added to the buffer.
A style intersects with the range if it overlaps with it at any point. For non-empty ranges, this means style.start < end and start < style.end.
Example Query Range: [5, 15)
0 5 10 15 20 25
|----|----|----|----|----| [---------) Query Range [5, 15)
[-------------------) Style [0, 20) (Contains query) -> Returned [----) Style [8, 12) (Inside query) -> Returned
[----------) Style [0, 10) (Overlap start) -> Returned
[----) Style [0, 5) (Touching start) -> NOT Returned [----------) Style [15, 25)(Touching end) -> NOT Returned
Example Collapsed Query: [10, 10)
0 5 10 15 20 25
|----|----|----|----|----| | Query Range [10, 10)
[-------------------) Style [0, 20) (Contains query) -> Returned
[----------) Style [0, 10) (Touching end) -> NOT Returned [----------) Style [10, 20)(Touching start) -> Returned
Parameters
| start | the inclusive start offset of the range |
| end | the exclusive end offset of the range |
Returns
| a list of TrackedRanges referencing the styles intersecting with the given range, returned in the order they were added to the buffer. |
removeStyle
fun removeStyle(trackedRange: TrackedRange<*>): Boolean
Removes the exact style represented by the given trackedRange from this buffer. This method only removes the specific style range tied to this TrackedRange object. Since trackedRange uniquely identifies a style range, it does not remove other styles that happen to occupy the same text range.
Parameters
| trackedRange | the TrackedRange referencing the specific style range to be removed. If the trackedRange was not added to this buffer, or has already been removed, this method will do nothing and return false. |
Returns
| true if the given trackedRange is found in the TextFieldBuffer and successfully removed, false otherwise. |