Skip to content

[WIP] Structured Text Input#20890

Open
Gillibald wants to merge 2 commits intoAvaloniaUI:masterfrom
Gillibald:feature/structuredTextInput
Open

[WIP] Structured Text Input#20890
Gillibald wants to merge 2 commits intoAvaloniaUI:masterfrom
Gillibald:feature/structuredTextInput

Conversation

@Gillibald
Copy link
Contributor

What does the pull request do?

New public contract

New unstable API surface in Avalonia.Input.TextInput:

  • IStructuredTextInput
  • ITextPointer
  • ITextRange
  • TextGranularity

Key design points:

  • Offsets are UTF-16 code unit offsets.
  • APIs are UI-thread only.
  • The contract includes:
    • Document/selection/caret/composition state access.
    • Text replacement and composition lifecycle operations.
    • Geometry and hit-testing methods for IME integration.
    • Boundary and enclosing range queries by granularity.
    • Change events for text, caret position, and composition state.

Core implementation in TextBox

TextBoxTextInputMethodClient now implements IStructuredTextInput.

Implementation behavior:

  • Uses TextBox.Text as the document source and clamps all pointer/range offsets to valid bounds.
  • Implements DocumentStart, DocumentEnd, and DocumentRange using local pointer/range wrappers.
  • Maps Selection directly to TextBox.SelectionStart/SelectionEnd.
  • Tracks composition using _compositionRange with normalization and equality checks.
  • ReplaceText performs in-place replacement and collapses caret at inserted text end.
  • SetCompositionText supports both:
    • replacing existing composition range, and
    • starting composition from current selection.
  • CommitComposition clears composition state.
  • Geometry APIs (GetFirstRectForRange, GetCaretRect, GetSelectionRects) use TextPresenter.TextLayout hit-testing and transform results to parent coordinates.
  • Hit-testing APIs (GetClosestPosition, GetCharacterRangeAtPoint) map points to nearest text positions/ranges.
  • Granularity APIs:
    • GetRangeEnclosing supports document, character, line, paragraph, word, sentence.
    • GetBoundaryPosition supports document, character, and boundaries derived from enclosing ranges.
  • Event batching (BeginChange) defers and coalesces notifications to avoid inconsistent intermediate states.

Compatibility note:

  • Legacy TextInputMethodClient members (SurroundingText, line-relative Selection) remain available for existing platform paths.
  • Structured paths use absolute document offsets through IStructuredTextInput.

Android bridge updates

AndroidInputMethod and AvaloniaInputConnection now branch on IStructuredTextInput availability:

  • Selection/composition updates sent to Android IME are derived from structured ranges when available.
  • IME edit operations are mapped directly to structured operations:
    • SetComposingRegion
    • SetComposingText
    • SetSelection
    • CommitText
    • DeleteSurroundingText
    • DeleteSurroundingTextInCodePoints
    • FinishComposingText
  • Extracted text, selected text, and before/after-cursor queries read from IStructuredTextInput document/range APIs.
  • Legacy queued command behavior remains as fallback for non-structured clients.

iOS bridge updates

TextInputResponder now uses structured operations whenever the client implements IStructuredTextInput:

  • Introduces StructuredClient and conversion helpers between UIKit ranges and structured ranges.
  • Routes editing/composition calls through structured APIs:
    • InsertText
    • TextInRange
    • ReplaceText
    • SetMarkedText
    • UnmarkText
  • Routes navigation/range requests through structured boundary and range APIs:
    • position movement by character/line boundaries
    • character range extension
  • Routes geometry/hit-testing through structured methods:
    • first rect for range
    • caret rect
    • closest position (global and constrained)
    • character range at point
    • selection rectangles
  • SelectedTextRange and MarkedTextRange map to structured selection/composition ranges.
  • Responder lifecycle now subscribes/unsubscribes to structured events (TextChanged, CaretPositionChanged, CompositionChanged) for IME state notifications.

Test coverage added

TextBoxTests now validates structured behavior, including:

  • Reading full document via DocumentRange.
  • Creating pointers with direction metadata.
  • Composition text updates and commit lifecycle.
  • Replacing selected ranges.
  • Emission of TextChanged, CompositionChanged, and CaretPositionChanged events.
  • Selection updates via structured range assignment.

Overall, the tests establish that the new structured model is functionally wired through TextBox and observable by IME bridges.

What is the current behavior?

What is the updated/expected behavior with this PR?

How was the solution implemented (if it's not obvious)?

Checklist

Breaking changes

Obsoletions / Deprecations

Fixed issues

@Gillibald Gillibald added area-textprocessing needs-api-review The PR adds new public APIs that should be reviewed. enhancement labels Mar 13, 2026
@Gillibald Gillibald force-pushed the feature/structuredTextInput branch from 38c6911 to 42c46bf Compare March 13, 2026 09:52
@avaloniaui-bot
Copy link

You can test this PR using the following package version. 12.0.999-cibuild0063355-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-textprocessing enhancement needs-api-review The PR adds new public APIs that should be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants