From 976a54d87cba22e21e83c7f719c516ec84bfc41e Mon Sep 17 00:00:00 2001 From: ALBIN BABU VARGHESE Date: Fri, 9 May 2025 19:00:46 -0400 Subject: [PATCH] Allow triple-click to select logical line (#18885) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes #18877, by iteratively checking to see if a line is wrapped and moving up or down accordingly. **Current behavior:** When a user triple-clicks on a line that’s visually wrapped by the terminal, only the single physical row that was clicked gets selected. **Expected behavior:** A triple-click like in xterm, should select the entire logical line including all of its wrapped segments, from the true start through its true end, regardless of where the wrap occurred. **Why it matters:** Logical line selection is what users expect when they’re trying to grab one command or output block in full. Limiting the selection to just the current physical row can lead to copy/paste mistakes and a confusing experience whenever a long line wraps. ## Validation Steps Performed I ran the existing tests using `Invoke-OpenConsoleTests` and they were passing and I was also able to test the build on my machine. I added a test case as well ## PR Checklist Closes #18877 --- src/cascadia/TerminalCore/TerminalSelection.cpp | 12 ++++++++++++ .../UnitTests_TerminalCore/SelectionTest.cpp | 15 +++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/cascadia/TerminalCore/TerminalSelection.cpp b/src/cascadia/TerminalCore/TerminalSelection.cpp index 707415015a..d588b67cb0 100644 --- a/src/cascadia/TerminalCore/TerminalSelection.cpp +++ b/src/cascadia/TerminalCore/TerminalSelection.cpp @@ -294,9 +294,21 @@ std::pair Terminal::_ExpandSelectionAnchors(std::pair 0 && buffer.GetRowByOffset(start.y - 1).WasWrapForced()) + { + --start.y; + } + // climb down to the last row that is wrapped + while (end.y + 1 < height && buffer.GetRowByOffset(end.y).WasWrapForced()) + { + ++end.y; + } start = { bufferSize.Left(), start.y }; end = { bufferSize.RightExclusive(), end.y }; break; diff --git a/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp b/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp index 1585fef905..d59ea73617 100644 --- a/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp +++ b/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp @@ -549,6 +549,21 @@ namespace TerminalCoreUnitTests ValidateLinearSelection(term, { 0, 10 }, { term.GetViewport().RightExclusive(), 10 }); } + TEST_METHOD(TripleClick_WrappedLine) + { + Terminal term{ Terminal::TestDummyMarker{} }; + DummyRenderer renderer{ &term }; + term.Create({ 10, 5 }, 0, renderer); + term.Write(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + + // Simulate click at (x,y) = (3,1) + auto clickPos = til::point{ 3, 1 }; + term.MultiClickSelection(clickPos, Terminal::SelectionExpansion::Line); + + // Validate selection area + ValidateLinearSelection(term, { 0, 0 }, { term.GetViewport().RightExclusive(), 2 }); + } + TEST_METHOD(TripleClickDrag_Horizontal) { Terminal term{ Terminal::TestDummyMarker{} };