Repository navigation
fix: InsertHyperlinkCommand uses DisplayText; undo/redo of a linked selection - #28
Merged
Merged
Conversation
DisplayText was documented as the link's display text but Execute never read it. When set (not empty/whitespace) the link now uses that text, inserted at the caret or replacing the selected text; when empty the selection is linked, or the URL is inserted as the text, as before. InsertHyperlinkAction now snapshots the affected paragraphs and resolves its range through paragraph anchors, like DeleteRangeAction, so undo restores the replaced text with its original formatting and redo after undo no longer throws on stale inline indices. HyperlinkEngine gains an InsertHyperlink overload taking displayText. The MAUI prompt only asks for a URL, so it is unchanged. 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
Unresolved insertion-boundary, snapshot-preservation, image-undo, and layout-cache issues can cause incorrect placement, content loss, or stale rendering.
4 open issues
What changed in this PR
Makes hyperlink insertion honor DisplayText and updates undo/redo to restore selected text and formatting.
Changes:
- Adds display-text support while preserving existing overloads.
- Uses paragraph snapshots and character-offset anchors for undo/redo.
- Adds command tests and updates documentation.
| File | Description |
|---|---|
| tests/MintedTextEditor.Core.Tests/CommandTests.cs | Tests display text, selection replacement, and undo. |
| src/MintedTextEditor.Core/Formatting/HyperlinkEngine.cs | Adds a display-text overload. |
| src/MintedTextEditor.Core/Editing/UndoableActions.cs | Adds snapshots and anchors for hyperlink undo/redo. |
| src/MintedTextEditor.Core/Commands/HyperlinkCommands.cs | Passes DisplayText to the undoable action. |
| docs/images-hyperlinks.md | Documents display-text behavior and overloads. |
| CHANGELOG.md | Records the hyperlink fixes. |
Review effort: Balanced
# Conflicts: # CHANGELOG.md
- Paragraph snapshots now hold the original paragraph and inline objects plus their state at capture time, and restore those same objects (recursively for link children) instead of building copies. An earlier InsertImageAction still finds its image after a later link insertion is undone, so undoing it removes the image and redo no longer duplicates it. LineBreak no longer comes back as text, and links keep non-text children. - Undo that reinserts paragraphs merged away by a multi-paragraph selection (InsertHyperlinkAction, DeleteRangeAction) reports BlockSplit, so LayoutCache drops every later block's cached layout. Both use one shared SnapshotHelper.RestoreBlocks, which only reinserts paragraphs no longer in the document; ApplyStyleAction uses it too, so each snapshot restores its own paragraph even with a table inside the range. - HyperlinkEngine inserts a link after an image or existing link when the caret is at that inline's end (where undo anchors resolve a caret at the start of the following text), instead of before it, and sets Parent on the link's children and on the split-off run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197tHRWhTiagB1MTsDuPkoa
michaelstonis
pushed a commit
that referenced
this pull request
Oct 21, 2026
…napshots SnapshotHelper rebuilt every inline from copied data on restore, so undo steps recorded earlier that hold the original objects (InsertHyperlinkAction, InsertImageAction) could no longer find them: insert a link, remove or format it, undo twice, and the link stayed. Snapshots also turned LineBreak into a "\n" text run and kept only TextRun children of hyperlinks. Adopt the identity-preserving SnapshotHelper from PR #28 (housekeeping/hyperlink-display-text) verbatim so the two PRs merge cleanly: snapshots keep each original inline (and paragraph) with its state, restore puts the same objects back, line breaks and other inline types are kept as themselves, and hyperlink children are captured recursively. The inline-only restore used by ApplyStyleAction and RemoveHyperlinkAction is now a small ApplyStyleAction.RestoreInlines wrapper outside SnapshotHelper. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197tHRWhTiagB1MTsDuPkoa
# Conflicts: # CHANGELOG.md
michaelstonis
added a commit
that referenced
this pull request
Oct 21, 2026
* fix: record character formatting and hyperlink removal for undo Bold/italic/underline/strikethrough/sub/superscript/clear-formatting commands, Ctrl+B/I/U, the font family/size dropdowns and the text/highlight colour pickers called FormattingEngine/FontFormattingEngine directly, so none of them could be undone. ApplyStyleAction existed but only took a fixed transform (the toggles decide on/off from the current runs), restored the paragraph style on undo, and paired snapshots with block indices by position, restoring the wrong paragraph when a table sat inside the range. ApplyStyleAction now also wraps any formatting operation, snapshots each paragraph with its block index, restores only the inlines on undo, and merges split runs after applying. EditorContext.ApplyCharacterFormatting pushes one ApplyStyleAction for a non-empty selection (keeping the selection on the same text) and leaves a collapsed selection to the engines' pending style, which is not recorded. The commands, keyboard shortcuts and MAUI dropdowns/pickers all go through it. HyperlinkEngine.RemoveHyperlink now keeps the link's runs and their styles instead of one plain run, and RemoveHyperlinkCommand pushes a new RemoveHyperlinkAction that snapshots the paragraph so undo restores the link. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197tHRWhTiagB1MTsDuPkoa * fix: address review — keep inline identity and lose nothing in undo snapshots SnapshotHelper rebuilt every inline from copied data on restore, so undo steps recorded earlier that hold the original objects (InsertHyperlinkAction, InsertImageAction) could no longer find them: insert a link, remove or format it, undo twice, and the link stayed. Snapshots also turned LineBreak into a "\n" text run and kept only TextRun children of hyperlinks. Adopt the identity-preserving SnapshotHelper from PR #28 (housekeeping/hyperlink-display-text) verbatim so the two PRs merge cleanly: snapshots keep each original inline (and paragraph) with its state, restore puts the same objects back, line breaks and other inline types are kept as themselves, and hyperlink children are captured recursively. The inline-only restore used by ApplyStyleAction and RemoveHyperlinkAction is now a small ApplyStyleAction.RestoreInlines wrapper outside SnapshotHelper. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197tHRWhTiagB1MTsDuPkoa --------- Co-authored-by: Claude <noreply@anthropic.com>
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
InsertHyperlinkCommand.DisplayTextwas documented as the link's display text, butExecutenever read it. It now works:DisplayTextset: a link with that text is inserted at the caret. If text is selected,DisplayTextreplaces the selection and becomes the link, like the "Text to display" field in most editors. ADisplayTextthat is only spaces counts as empty.DisplayTextempty: behaves as before. The selection becomes the link, or the URL is inserted as the link text when nothing is selected.Also fixed: after undoing a link made from a selection, redo threw
ArgumentOutOfRangeException, and the undo had already dropped the original text's formatting.InsertHyperlinkActionnow saves the affected paragraphs before inserting and locates its range by character offsets, the same wayDeleteRangeActionworks. That fixes both problems and also restores paragraphs that a multi-paragraph selection merged. The existing 3-argument constructor andHyperlinkEngine.InsertHyperlinkoverload still work, and there is a new overload that takesdisplayText.Testing
CommandTests, each also checking undo:Not included
RemoveHyperlinkis still not recorded for undo.Both are noted as follow-ups.
Checklist
Generated by Claude Code