Skip to content

fix: typing keeps the caret's formatting; toolbar shows it; SelectionChanged on undo/load - #37

Merged
michaelstonis merged 5 commits into
mainfrom
housekeeping/caret-formatting
Oct 21, 2026
Merged

michaelstonis merged 5 commits into
mainfrom
housekeeping/caret-formatting

Conversation

@michaelstonis

Copy link
Copy Markdown
Contributor

Summary

Three related bugs the housekeeping work turned up:

  1. Typing ignored the formatting at the caret. With no selection, new text always got the default style, so typing at the end of a bold word wasn't bold. It now takes the style of the character before the caret, or the character after it at the start of a paragraph; images and line breaks are skipped. A pending style (one picked from the toolbar before typing) still takes priority. The new DocumentEditor.GetInsertionStyle and FormattingEngine.GetEffectiveCaretStyle do this, and the toolbar uses the same code.
    • Links: typing at either end of a hyperlink now adds plain text next to it instead of growing the link. Before, typing right after a link extended it. Typing inside a link still edits it.
    • Pending style: it now starts from the caret's style instead of the default. So toggling Italic inside bold text gives bold-italic, and toggling Bold off inside bold text really turns it off.
  2. The toolbar showed no active state at a bare caret. With nothing selected, the Bold, Italic, Underline, Strikethrough, Subscript and Superscript buttons now reflect the caret's effective style.
  3. Undo, redo and load didn't raise SelectionChanged. Undo and redo now raise it when the caret moves. LoadHtml and LoadMarkdown always raise it, because the document is replaced.

Testing

  • 13 new tests in CaretFormattingTests cover:
    • typing after bold text;
    • the start of a paragraph and an empty paragraph;
    • the pending style winning and keeping inherited formatting;
    • typing at either edge of a link, and inside a link;
    • undo after typing next to a link;
    • toolbar state at a caret.
  • One existing test that expected the old behaviour was updated and renamed.
  • Core.Tests pass (807) and SkiaSharp.Tests pass (29). The SkiaSharp Release build has 0 warnings, and the MAUI shared code compiles cleanly.

Found but not changed here

These are tracked as follow-ups:

  • A new paragraph created by pressing Enter after bold text doesn't carry the bold.
  • A pending style isn't cleared when the caret moves somewhere else.
  • Plain-text paste and find/replace still insert text in the default style.

Checklist

  • CHANGELOG Fixed entries under Unreleased
  • docs/formatting.md and commands-events.md updated

Generated by Claude Code

With nothing selected, typed text used TextStyle.Default unless a pending
style had been picked, so typing after a bold word was not bold. Typed text
now inherits the style of the character before the caret (or after it at a
paragraph start) via the new DocumentEditor.GetInsertionStyle; a pending
style still wins. Pending styles now start from the caret's style, so
toggling Bold inside bold text turns it off instead of keeping it on.
FormattingEngine.GetEffectiveCaretStyle combines both rules and is shared by
the input controller and the toolbar.

Typing at the start or end of a hyperlink now inserts plain text next to
the link instead of extending it; typing inside a link still edits it.

ToolbarRenderer.UpdateToggleStates showed toggles active only for a
selection; at a collapsed caret it now reflects the effective caret style.

MintedEditorView.Undo/Redo raise SelectionChanged when they move the caret,
and LoadHtml/LoadMarkdown raise it after resetting the caret.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0197tHRWhTiagB1MTsDuPkoa
Copilot AI balanced review requested due to automatic review settings October 21, 2026 16:44

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Hyperlink-boundary handling incorrectly moves replacement text outside existing links.

1 open issue
What changed in this PR

Aligns typing and toolbar formatting with the caret’s style and improves selection notifications.

Changes:

  • Inherits caret formatting while honoring pending styles.
  • Inserts text outside hyperlink boundaries.
  • Raises selection-change events after loading and caret-moving undo/redo operations.
File Description
tests/​MintedTextEditor.Core.Tests/​CharacterFormattingTests.cs Updates subsequent-typing expectations.
tests/​MintedTextEditor.Core.Tests/​CaretFormattingTests.cs Adds caret formatting and hyperlink tests.
src/​MintedTextEditor.Maui/​MintedEditorView.cs Adds selection notifications.
src/​MintedTextEditor.Core/​Toolbar/​ToolbarRenderer.cs Reflects effective caret formatting.
src/​MintedTextEditor.Core/​Input/​EditorInputController.cs Applies effective formatting when typing.
src/​MintedTextEditor.Core/​Formatting/​FormattingEngine.cs Resolves caret and pending styles.
src/​MintedTextEditor.Core/​Formatting/​FontFormattingEngine.cs Seeds pending formatting from caret style.
src/​MintedTextEditor.Core/​Document/​DocumentEditor.cs Adds style lookup and hyperlink-boundary handling.
docs/​formatting.md Documents formatting behavior.
docs/​commands-events.md Documents selection notifications.
CHANGELOG.md Records the fixes.

Review effort: Balanced

The link-boundary rule (typing at the start or end of a hyperlink does not
extend it) lived in DocumentEditor.InsertText, so it also applied after a
selection or find match had been deleted: replacing "ite" in the linked
word "site" with "pot" gave linked "s" plus unlinked "pot".

The rule is now opt-in through a new InsertText overload and
InsertTextAction.EscapeHyperlinkBoundary. The input controller sets it only
for text typed or pasted at a caret that was collapsed to begin with, and
keeps the decision for characters typed straight after, so typing a word
over a selection stays in the link. When the replaced selection starts at
the start of a link, the insertion point is moved back into that link, and
InsertTextAction keeps that affinity on redo. The 4-argument InsertText
(used by find and replace) inserts into the link again, whichever order
Replace/ReplaceAll delete and insert in.

Also: Enter at the end of formatted text gives the new paragraph an empty
run with the caret's style, so text typed after Enter keeps it (e.g. bold).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0197tHRWhTiagB1MTsDuPkoa
# Conflicts:
#	CHANGELOG.md
#	src/MintedTextEditor.Core/Editing/UndoableActions.cs
#	src/MintedTextEditor.Maui/MintedEditorView.cs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0197tHRWhTiagB1MTsDuPkoa
@michaelstonis
michaelstonis merged commit b15d04b into main Oct 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants