Repository navigation
fix: pending style applies only at its caret; plain paste uses typing style; notify IME on undo/redo - #40
Merged
Conversation
…tified on undo/redo A format picked at a collapsed caret (e.g. Bold with nothing selected) kept applying wherever the user typed next, even after moving the caret. The FormattingEngine and FontFormattingEngine now record where the pending style was picked (PendingStylePosition) and DiscardPendingStyleIfMoved drops it once the selection is no longer that caret (compared by paragraph and character offset, so run-boundary positions match). The input controller discards stale pending styles after handled keys, pointer input and before typing, pasting or Enter (which still carries the style into the new paragraph); the toolbar and MintedEditorView's formatting state do the same, so moving the selection from code is covered too. Plain-text paste inserted TextStyle.Default. HandlePasteAsync now uses the same insertion style as typing (pending style, else the caret's style), and ClipboardOperations.PasteAsync inherits the caret's style. MintedEditorView.Undo()/Redo() (toolbar buttons and public API) did not tell the platform IME that the text and selection changed, unlike the Ctrl+Z path; they now call NotifyImeSelectionChanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197tHRWhTiagB1MTsDuPkoa
There was a problem hiding this comment.
🟡 Changes recommended
Pending-style validation still mishandles origin ranges and deletion-related caret or selection changes.
3 open issues
What changed in this PR
This PR aligns pending formatting and plain-text paste with caret-based typing behavior, and synchronizes platform keyboards after undo/redo.
Changes:
- Tracks pending styles by caret position.
- Makes plain-text paste inherit insertion formatting.
- Adds regression tests, documentation, and IME notifications.
| File | Description |
|---|---|
| tests/MintedTextEditor.Core.Tests/PendingStyleTests.cs | Tests pending styles and paste formatting. |
| tests/MintedTextEditor.Core.Tests/CharacterFormattingTests.cs | Anchors pending formats at the test caret. |
| src/MintedTextEditor.Maui/MintedEditorView.cs | Refreshes formatting state and notifies IME after history changes. |
| src/MintedTextEditor.Core/Toolbar/ToolbarRenderer.cs | Discards stale styles before updating toggles. |
| src/MintedTextEditor.Core/Input/EditorInputController.cs | Validates pending styles and shares insertion formatting. |
| src/MintedTextEditor.Core/Formatting/FormattingEngine.cs | Tracks character-formatting caret anchors. |
| src/MintedTextEditor.Core/Formatting/FontFormattingEngine.cs | Tracks font-formatting caret anchors. |
| src/MintedTextEditor.Core/Editing/ClipboardOperations.cs | Applies inherited formatting to pasted text. |
| docs/formatting.md | Documents caret-scoped styles and paste behavior. |
| CHANGELOG.md | Records formatting and IME changes. |
Review effort: Balanced
Finding 1: TextRange.Empty was default(TextRange), whose positions have cell coordinates 0/0 (so IsInTableCell is true), while the caret starts at -1/-1. ToggleBold(doc, TextRange.Empty) followed by typing at the initial caret therefore discarded the pending style. TextRange.Empty now holds explicit (0,0,0) positions, and the pending-style comparison ignores cell coordinates outside table blocks, so default(TextRange) works too; cells in a table stay distinct. Finding 2: the comparison resolved both the saved and the current position against the edited document, so Backspace at the end of a run clamped the saved offset to the new caret and the pending style survived. The engines now store the paragraph and character offset when the pending style is picked (PendingStyleAnchor) and compare the caret against that; Enter re-anchors it in the new paragraph. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197tHRWhTiagB1MTsDuPkoa
… key Finding 3: HandleKeyDown only checked the pending style after the key. With Bold picked at offset 5 and the selection then set to [5,8] from code, Backspace or Delete collapsed the selection back to offset 5, so the check afterwards saw the original caret and kept the stale pending style. The controller now also discards it before handling the key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197tHRWhTiagB1MTsDuPkoa
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
FormattingEngine.PendingStylePosition/FontFormattingEngine.PendingStylePositionandDiscardPendingStyleIfMoved(doc, selection).EditorInputController.HandlePasteAsyncnow uses the same style as typing: the pending style, otherwise the caret's formatting. Before, it usedTextStyle.Default.ClipboardOperations.PasteAsyncnow also takes the caret's formatting.MintedEditorView.Undo()andRedo(), from the toolbar and the public API, now callNotifyImeSelectionChanged(), as the Ctrl+Z path already did. Without this, Android and iOS keyboards could keep editing stale text.Tests
PendingStyleTestswith 19 cases. They cover:ClipboardOperations.CharacterFormattingTestsrelied on a pending style picked away from the caret. They now pick it at the caret.Generated by Claude Code