From 750db8e71c6536707b404f2e21c92dddad527921 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Fri, 28 Jun 2024 00:41:01 +0100 Subject: [PATCH] Fix 'incsearch'+'wrapscan' at bottom of file If all results are before the caret, make sure it's still possible to highlight the closest match if 'wrapscan' is enabled Fixes VIM-3505 --- .../idea/vim/helper/SearchHighlightsHelper.kt | 26 ++++++++++++--- .../plugins/ideavim/group/SearchGroupTest.kt | 32 +++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/maddyhome/idea/vim/helper/SearchHighlightsHelper.kt b/src/main/java/com/maddyhome/idea/vim/helper/SearchHighlightsHelper.kt index 75958d0ae2..6e4e95cbb0 100644 --- a/src/main/java/com/maddyhome/idea/vim/helper/SearchHighlightsHelper.kt +++ b/src/main/java/com/maddyhome/idea/vim/helper/SearchHighlightsHelper.kt @@ -210,12 +210,28 @@ private fun findClosestMatch( return -1 } - val sortedResults = results.sortedBy { it.startOffset }.let { if (!forwards) it.reversed() else it } - val nextIndex = sortedResults.indexOfFirst { - if (forwards) it.startOffset > initialOffset else it.startOffset < initialOffset + val sortedResults = if (forwards) { + results.sortedBy { it.startOffset } + } else { + results.sortedByDescending { it.startOffset } } - val toDrop = (nextIndex + count - 1).let { if (injector.globalOptions().wrapscan) it % results.size else it } - return sortedResults.drop(toDrop).firstOrNull()?.startOffset ?: -1 + val closestIndex = if (forwards) { + sortedResults.indexOfFirst { it.startOffset > initialOffset } + } + else { + sortedResults.indexOfFirst { it.startOffset < initialOffset } + } + + if (closestIndex == -1 && !injector.globalOptions().wrapscan) { + return -1 + } + + val nextIndex = closestIndex.coerceAtLeast(0) + (count - 1) + if (nextIndex >= sortedResults.size && !injector.globalOptions().wrapscan) { + return -1 + } + + return sortedResults[nextIndex % results.size].startOffset } internal fun highlightSearchResults(editor: Editor, pattern: String, results: List, currentMatchOffset: Int) { diff --git a/src/test/java/org/jetbrains/plugins/ideavim/group/SearchGroupTest.kt b/src/test/java/org/jetbrains/plugins/ideavim/group/SearchGroupTest.kt index e94cebdfab..b6cea064e7 100644 --- a/src/test/java/org/jetbrains/plugins/ideavim/group/SearchGroupTest.kt +++ b/src/test/java/org/jetbrains/plugins/ideavim/group/SearchGroupTest.kt @@ -1063,6 +1063,38 @@ class SearchGroupTest : VimTestCase() { assertPosition(1, 14) } + @Test + fun `test incsearch + hlsearch at bottom of file with wrapscan`() { + // Make sure the caret wraps during incsearch + configureByText( + """ + |Lorem ipsum dolor sit amet, + |consectetur adipiscing elit + |Sed in orci ${c}mauris. + |Cras id tellus in ex imperdiet egestas. + """.trimMargin() + ) + enterCommand("set incsearch hlsearch wrapscan") + typeText("/it") + assertPosition(0, 19) + } + + @Test + fun `test incsearch + hlsearch at bottom of file with nowrapscan`() { + // This will highlight the occurrences above/before the caret, but should not move the caret + configureByText( + """ + |Lorem ipsum dolor sit amet, + |consectetur adipiscing elit + |Sed in orci ${c}mauris. + |Cras id tellus in ex imperdiet egestas. + """.trimMargin() + ) + enterCommand("set incsearch hlsearch nowrapscan") + typeText("/it") + assertPosition(2, 12) + } + @TestWithoutNeovim(SkipNeovimReason.OPTION) @Test fun `test incsearch moves caret to start of first match (backwards)`() {