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 e27be4d7c..372f49897 100644 --- a/src/main/java/com/maddyhome/idea/vim/helper/SearchHighlightsHelper.kt +++ b/src/main/java/com/maddyhome/idea/vim/helper/SearchHighlightsHelper.kt @@ -17,6 +17,7 @@ import com.intellij.openapi.editor.markup.HighlighterLayer import com.intellij.openapi.editor.markup.HighlighterTargetArea import com.intellij.openapi.editor.markup.RangeHighlighter import com.intellij.openapi.editor.markup.TextAttributes +import com.intellij.util.application import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.globalOptions import com.maddyhome.idea.vim.api.injector @@ -30,6 +31,7 @@ import com.maddyhome.idea.vim.state.mode.inVisualMode import org.jetbrains.annotations.Contract import java.awt.Font import java.util.* +import javax.swing.Timer internal fun updateSearchHighlights( pattern: String?, @@ -84,6 +86,12 @@ internal fun addSubstitutionConfirmationHighlight(editor: Editor, start: Int, en ) } +val removeHighlightsEditors = mutableListOf<Editor>() +val removeHighlightsTimer = Timer(400) { + removeHighlightsEditors.forEach(::removeSearchHighlights) + removeHighlightsEditors.clear() +} + /** * Refreshes current search highlights for all visible editors */ @@ -125,27 +133,43 @@ private fun updateSearchHighlights( // hlsearch (+ incsearch/noincsearch) // Make sure the range fits this editor. Note that Vim will use the same range for all windows. E.g., given // `:1,5s/foo`, Vim will highlight all occurrences of `foo` in the first five lines of all visible windows - val vimEditor = editor.vim - val editorLastLine = vimEditor.lineCount() - 1 - val searchStartLine = searchRange?.startLine ?: 0 - val searchEndLine = (searchRange?.endLine ?: -1).coerceAtMost(editorLastLine) - if (searchStartLine <= editorLastLine) { - val results = - injector.searchHelper.findAll( - vimEditor, - pattern, - searchStartLine, - searchEndLine, - shouldIgnoreCase(pattern, shouldIgnoreSmartCase) - ) - if (results.isNotEmpty()) { - if (editor === currentEditor?.ij) { - currentMatchOffset = findClosestMatch(results, initialOffset, count1, forwards) + val isSearching = injector.commandLine.getActiveCommandLine() != null + application.invokeLater { + val vimEditor = editor.vim + val editorLastLine = vimEditor.lineCount() - 1 + val searchStartLine = searchRange?.startLine ?: 0 + val searchEndLine = (searchRange?.endLine ?: -1).coerceAtMost(editorLastLine) + if (searchStartLine <= editorLastLine) { + val visibleArea = editor.scrollingModel.visibleAreaOnScrollingFinished + val visibleTopLeft = visibleArea.location + val visibleBottomRight = visibleArea.location.apply { translate(visibleArea.width, visibleArea.height) } + val visibleStartOffset = editor.logicalPositionToOffset(editor.xyToLogicalPosition(visibleTopLeft)) + val visibleEndOffset = editor.logicalPositionToOffset(editor.xyToLogicalPosition(visibleBottomRight)) + val visibleStartLine = editor.document.getLineNumber(visibleStartOffset) + val visibleEndLine = editor.document.getLineNumber(visibleEndOffset) + removeSearchHighlights(editor) + + val results = + injector.searchHelper.findAll( + vimEditor, + pattern, + searchStartLine.coerceAtLeast(visibleStartLine), + searchEndLine.coerceAtMost(visibleEndLine), + shouldIgnoreCase(pattern, shouldIgnoreSmartCase) + ) + if (results.isNotEmpty()) { + if (editor === currentEditor?.ij) { + currentMatchOffset = findClosestMatch(results, initialOffset, count1, forwards) + } + highlightSearchResults(editor, pattern, results, currentMatchOffset) + if (!isSearching) { + removeHighlightsEditors.add(editor) + removeHighlightsTimer.restart() + } } - highlightSearchResults(editor, pattern, results, currentMatchOffset) } + editor.vimLastSearch = pattern } - editor.vimLastSearch = pattern } else if (shouldAddCurrentMatchSearchHighlight(pattern, showHighlights, initialOffset)) { // nohlsearch + incsearch. Even though search highlights are disabled, we still show a highlight (current editor // only), because 'incsearch' is active. But we don't show a search if Visual is active (behind Command-line of @@ -179,6 +203,7 @@ private fun updateSearchHighlights( } } + removeHighlightsTimer.restart() return currentEditorCurrentMatchOffset } @@ -204,7 +229,7 @@ private fun removeSearchHighlights(editor: Editor) { */ @Contract("_, _, false -> false; _, null, true -> false") private fun shouldAddAllSearchHighlights(editor: Editor, newPattern: String?, hlSearch: Boolean): Boolean { - return hlSearch && newPattern != null && newPattern != editor.vimLastSearch && newPattern != "" + return hlSearch && newPattern != null && newPattern != "" } private fun findClosestMatch( diff --git a/src/main/java/com/maddyhome/idea/vim/listener/VimListenerManager.kt b/src/main/java/com/maddyhome/idea/vim/listener/VimListenerManager.kt index e7e8a6410..9a0550dbd 100644 --- a/src/main/java/com/maddyhome/idea/vim/listener/VimListenerManager.kt +++ b/src/main/java/com/maddyhome/idea/vim/listener/VimListenerManager.kt @@ -425,7 +425,7 @@ internal object VimListenerManager { MotionGroup.fileEditorManagerSelectionChangedCallback(event) FileGroup.fileEditorManagerSelectionChangedCallback(event) - VimPlugin.getSearch().fileEditorManagerSelectionChangedCallback(event) +// VimPlugin.getSearch().fileEditorManagerSelectionChangedCallback(event) IjVimRedrawService.fileEditorManagerSelectionChangedCallback(event) VimLastSelectedEditorTracker.setLastSelectedEditor(event.newEditor) }