Fixes #5270, #5273, #5281. Fix MarkdownView selection overlay bugs#5282
Merged
YourRobotOverlord merged 6 commits intoMay 9, 2026
Conversation
…nce delimiters When copying a partial selection that starts or ends inside a fenced code block, the copied text should not include the fence delimiters unless the selection actually crosses from non-code content into the code block. Root cause: GetSelectedText() unconditionally injected the opening fence whenever it first encountered a code-block line, and unconditionally injected the closing fence at the end of the loop if still inside a code block. This meant any selection touching a code block line would include fences, even if the selection was entirely within the code block. Fix: Replace the unconditional fence injection with two tracking flags: - selectionHasNonCodeContent: set true when any non-code line is processed. Opening fence is only emitted when transitioning from non-code -> code. - codeOpenFenceEmitted: tracks whether an opening fence was actually emitted for the current code block. Closing fence is only emitted when the matching opening fence was emitted. This ensures: - Selection entirely within a code block -> no fences (regardless of position) - Selection starting before a code block -> opening fence included - Selection ending after a code block -> closing fence included Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…nSubViewRows ContentToScreen expects content-relative coordinates (where 0 = top of the content area), not viewport-relative coordinates. The old code passed drawRow (= lineIdx - Viewport.Y), so ContentToScreen subtracted Viewport.Y a second time, reading graphemes from the wrong screen row. With a non-zero scroll offset this caused the selection overlay to copy characters from an incorrect row (e.g. the table header) over the correct row (the table body), making body cell values disappear. Fix: pass lineIdx (content-relative) instead of drawRow. Added regression test SelectionOverlay_On_Table_Is_Synced_When_Scrolled that scrolls a Markdown view past introductory text so only a table is visible, activates a full selection, and asserts the body-row values (1, 2) remain in the screen buffer. The test height (5) is intentionally less than the total content height (7) so Viewport.Y = 2 is not clamped. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e fence delimiters from partial code-block selections Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
DrawSelectionOverlayOnSubViewRows was applying the selection attribute to every column of a subview row unconditionally. On the start/end lines of a selection this caused unselected columns to be highlighted, making it look as though the entire line was selected even when only part of it was. Fix: call IsInSelection(lineIdx, col + Viewport.X) per column, mirroring the per-grapheme check already in DrawRenderedLine for plain text lines. For non-selected columns the original Cell.Attribute from ScreenContents is restored so the subview styling is preserved. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Collaborator
Author
DrawSelectionOverlayOnSubViewRows reads graphemes from ScreenContents (previous frame) and re-draws them with the selection attribute. Popovers draw before MarkdownView in the application draw loop, so their menu items are already written to the screen buffer when the overlay runs. Re-drawing those cells with stale ScreenContents graphemes silently erases the popover's content. Fix: compute the active popover's content view screen rect before the cell loop and skip any cell that falls inside it. The popover's draws are preserved; the selection highlight still covers all other cells. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced May 21, 2026
This was referenced May 28, 2026
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.

Copilot Sessions
766860d7-4a69-4edf-b25c-cd362531af5a, cc36ca80-1ae3-4e1c-a9f7-6230152a804e
Fixes #5270, #5273, and #5281.
Summary
Three related bugs in
MarkdownView's selection overlay, all fixed inMarkdownView.Drawing.csandMarkdownView.Selection.cs.#5270 — Selection overlay out of sync when scrolled
DrawSelectionOverlayOnSubViewRows()calledContentToScreen(new Point(0, drawRow))wheredrawRow = lineIdx - Viewport.Y(viewport-relative).ContentToScreeninternally subtractsViewport.Y, so with any scroll offset the overlay read graphemes from the wrong screen row — overwriting body content with header content.Fix: Pass
lineIdx(content-relative) instead ofdrawRow.#5273 — Partial code-block selections include unwanted fence delimiters
GetSelectedText()unconditionally injected an opening fence when entering a code block and always appended a closing fence when the selection ended inside a block.Fix: Added
selectionHasNonCodeContentandcodeOpenFenceEmittedflags. Opening fence is only emitted when entering a code block after non-code content has been seen. Trailing fence is no longer appended for selections that end inside a block.#5281 — Selection highlight covers entire row in code blocks and tables
DrawSelectionOverlayOnSubViewRows()applied the selection attribute to every column unconditionally. Plain-text lines already use a per-graphemeIsInSelection()check — the subview overlay path was missing the equivalent.Fix: Call
IsInSelection(lineIdx, col + Viewport.X)per column. For non-selected columns, restore the originalCell.AttributefromScreenContentsso syntax-highlighted styling is preserved.Tests
6 new regression tests in
MarkdownViewSelectionTests.cs:SelectionOverlay_On_Table_Is_Synced_When_Scrolled(Markdown text selection overlay is out of sync with the actual selected text #5270)PartialSelection_InsideCodeBlock_DoesNotIncludeFenceDelimiters(Markdown - Copied partial selection from inside codeblock should not contain delimiters #5273)PartialSelection_StartBeforeCodeBlock_EndInside_HasOpeningFenceOnly(Markdown - Copied partial selection from inside codeblock should not contain delimiters #5273)PartialSelection_StartInsideCodeBlock_EndAfter_HasClosingFenceOnly(Markdown - Copied partial selection from inside codeblock should not contain delimiters #5273)PartialSelection_AllLinesOfCodeBlock_FromFirstLine_NoFences(Markdown - Copied partial selection from inside codeblock should not contain delimiters #5273)SelectionOverlay_On_CodeBlock_HighlightsOnlySelectedColumns(MarkdownView: Selection highlight covers entire row in code blocks and tables, even for partial selections #5281)