Fixes #4892. OSC 8 hyperlink rendering does not clean up#5254
Conversation
Two paths leak OSC 8 hyperlink state into adjacent rendering: 1. In `OutputBufferImpl.SetAttributeAndDirty`, when a cell that previously carried a URL is overdrawn by content with no `CurrentUrl` set (e.g. a parent view filling its content area, or a Link whose displayed text shrank), the cell becomes dirty but the stale entry stays in `_urlMap`. The next render wraps that cell in OSC 8, so unrelated content appears hyperlinked. Now the entry is removed when `CurrentUrl` is null/empty. 2. In `OutputBase.Write`, when dirty cells with a URL are flushed mid-row because a clean cell follows, the OSC 8 start sequence is emitted to the terminal but `outputStringBuilder` is cleared while `_lastUrl` stays set. If the row ends without another flush the existing `outputStringBuilder.Length <= 0` early-`continue` skips the OSC 8 close, leaving the hyperlink open across the row boundary so later rows render as part of the link. Now the close is emitted at end of row whenever `_lastUrl` is set. Adds three regression tests in `OutputBaseTests`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@harder I'm still seeing hyperlinks in the |
Of course. Please open the UICatalog Editor scenario. You will see several URL links. Try deleting all the text and moving the mouse along the lines, and you will see that the underlines of the URL links will appear. Or without delete simply navigating through the pages or scrolling the gear up and down and you will also see the underlines appear. At least, this is true when using Windows Terminal. |
|
Thank you! That was a big help. I see the issue with underlines persisting intermittently when scrolling the mousesheel up or down on my MacOS warp terminal. And with Windows Terminal on my Windows laptop, I can repro both issues. It looks like these are related to the same OSC 8 rendering code as what was fixed in this PR, but separate bugs that already existed and I didn't notice when testing earlier. I'm creating a new issue and PR now! |
Fixes #4892
Summary
Two distinct paths leak OSC 8 hyperlink state into adjacent rendering, producing the visual artifact reported in #4892 (text near a
Linkrendered as if it were part of the hyperlink).1. Stale entries in the cell URL map (
OutputBufferImpl.SetAttributeAndDirty)SetAttributeAndDirtypreviously only wrote to_urlMapwhenCurrentUrlwas non-empty and never cleared existing entries. When a cell that previously carried a URL was overdrawn by content with noCurrentUrlset — for example a parent view filling its content area, or aLinkwhose displayed text shrank - the cell became dirty but the stale URL persisted in_urlMap. On the next render that cell was wrapped in OSC 8 sequences, so unrelated content rendered as a hyperlink.Fix: when
CurrentUrlis null/empty, remove the entry for that cell from_urlMap.2. OSC 8 close skipped at row boundary (
OutputBase.Write)When dirty cells with a URL are flushed mid-row because a clean cell follows,
WriteToConsolewrites the OSC 8 start sequence + cell content to the terminal and clearsoutputStringBuilder, but_lastUrlstays set. If the row ends without another flush, the existingif (outputStringBuilder.Length <= 0) { continue; }early-continueskipped the end-of-row OSC 8 close. The hyperlink stayed open in the terminal across the row boundary, so subsequent rows rendered as part of the link.Fix: at end of row, if
_lastUrlis still set, emit the OSC 8 close even when nothing else is buffered. Legacy-console path is unchanged (no OSC 8 emitted).Tests
Three regression tests added in
Tests/UnitTestsParallelizable/Drivers/Output/OutputBaseTests.cs:Write_UrlFollowedByCleanCells_ClosesHyperlinkAtRowEnd— covers fix Add resizing support to the core #2AddStr_NoCurrentUrl_ClearsStaleUrlMapping— covers fix There is a problem with the high-intensity colors, they are not showing up #1AddStr_DifferentUrl_OverwritesUrlMapping— guards the URL-clear path against breaking re-assignment whenCurrentUrlchangesAll 16,847 parallelizable tests and 73 non-parallelizable tests pass.
To pull down this PR locally:
git remote add copilot https://github.com/harder/Terminal.Gui.git
git fetch copilot fix/4892-osc8-link-cleanup
git checkout copilot/fix/4892-osc8-link-cleanup