mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-03-07 21:32:52 +01:00
Improve performance of gn command
This commit is contained in:
parent
b795c62ab7
commit
eeea093bb8
src/com/maddyhome/idea/vim/group
test/org/jetbrains/plugins/ideavim/gn
@ -1352,31 +1352,28 @@ public class MotionGroup {
|
||||
}
|
||||
|
||||
public int selectNextSearch(@NotNull Editor editor, int count, boolean forwards) {
|
||||
TextRange nextRange = SearchGroup.findCurrentOrNextSearch(editor, count, forwards);
|
||||
if (nextRange == null) {
|
||||
return -1;
|
||||
}
|
||||
final int startOffset = startOffset(nextRange, forwards);
|
||||
TextRange current = VimPlugin.getSearch().findUnderCaret(editor);
|
||||
final Caret caret = editor.getCaretModel().getPrimaryCaret();
|
||||
|
||||
CommandState.Mode currentMode = CommandState.getInstance(editor).getMode();
|
||||
if (currentMode == CommandState.Mode.VISUAL) {
|
||||
if (atEdgeOfRange(nextRange, editor, forwards)) {
|
||||
nextRange = SearchGroup.findNextSearch(editor, count, forwards);
|
||||
if (current == null || CommandStateHelper.inVisualMode(editor) && atEdgeOfGnRange(current, editor, forwards)) {
|
||||
current = VimPlugin.getSearch().findNextSearchForGn(editor, count, forwards);
|
||||
if (current == null) return -1;
|
||||
}
|
||||
else {
|
||||
if (count > 1) {
|
||||
current = VimPlugin.getSearch().findNextSearchForGn(editor, count - 1, forwards);
|
||||
if (current == null) return -1;
|
||||
}
|
||||
}
|
||||
final int endOffset = endOffset(nextRange, forwards);
|
||||
|
||||
for (Caret caret : editor.getCaretModel().getAllCarets()) {
|
||||
MotionGroup.moveCaret(editor, caret, startOffset);
|
||||
if (currentMode != CommandState.Mode.VISUAL) {
|
||||
VimPlugin.getVisualMotion().enterVisualMode(editor, CommandState.SubMode.VISUAL_CHARACTER);
|
||||
}
|
||||
MotionGroup.moveCaret(editor, caret, endOffset);
|
||||
if (!CommandStateHelper.inVisualMode(editor)) {
|
||||
MotionGroup.moveCaret(editor, caret, gnStartOffset(current, forwards));
|
||||
VimPlugin.getVisualMotion().enterVisualMode(editor, CommandState.SubMode.VISUAL_CHARACTER);
|
||||
}
|
||||
return endOffset;
|
||||
return gnEndOffset(current, forwards);
|
||||
}
|
||||
|
||||
private boolean atEdgeOfRange(@NotNull TextRange nextRange, @NotNull Editor editor, boolean forwards) {
|
||||
private boolean atEdgeOfGnRange(@NotNull TextRange nextRange, @NotNull Editor editor, boolean forwards) {
|
||||
int currentPosition = editor.getCaretModel().getOffset();
|
||||
if (forwards) {
|
||||
return nextRange.getEndOffset() - 1 == currentPosition;
|
||||
@ -1386,13 +1383,12 @@ public class MotionGroup {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private int startOffset(TextRange nextRange, boolean forwards) {
|
||||
return forwards ? nextRange.getStartOffset() : Math.max(nextRange.getEndOffset() - 1, 0);
|
||||
private int gnEndOffset(@NotNull TextRange nextRange, boolean forwards) {
|
||||
return forwards ? Math.max(nextRange.getEndOffset() - 1, 0) : nextRange.getStartOffset();
|
||||
}
|
||||
|
||||
private int endOffset(TextRange nextRange, boolean forwards) {
|
||||
return forwards ? Math.max(nextRange.getEndOffset() - 1, 0) : nextRange.getStartOffset();
|
||||
private int gnStartOffset(@NotNull TextRange range, boolean forwards) {
|
||||
return forwards ? range.getStartOffset() : Math.max(range.getEndOffset() - 1, 0);
|
||||
}
|
||||
|
||||
private int lastFTCmd = 0;
|
||||
|
@ -619,49 +619,24 @@ public class SearchGroup {
|
||||
}
|
||||
}
|
||||
|
||||
private static Optional<TextRange> findCurrent(@NotNull Editor editor, @NotNull String pattern, final int offset) {
|
||||
return findAll(editor, pattern, 0, -1, shouldIgnoreCase(pattern, false))
|
||||
.stream()
|
||||
.filter(range -> range.contains(offset))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static TextRange findNext(@NotNull Editor editor,
|
||||
@NotNull String pattern,
|
||||
final int offset,
|
||||
boolean ignoreCase,
|
||||
public static TextRange findNext(@NotNull Editor editor, @NotNull String pattern, final int offset, boolean ignoreCase,
|
||||
final boolean forwards) {
|
||||
return findNext(editor, pattern, offset, ignoreCase, forwards, 1);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static TextRange findNext(@NotNull Editor editor,
|
||||
@NotNull String pattern,
|
||||
final int offset,
|
||||
boolean ignoreCase,
|
||||
final boolean forwards,
|
||||
final int count) {
|
||||
if (count <= 0) {
|
||||
return null;
|
||||
}
|
||||
final List<TextRange> results =
|
||||
new ArrayList<>(findAll(editor, pattern, 0, -1, shouldIgnoreCase(pattern, ignoreCase)));
|
||||
final List<TextRange> results = findAll(editor, pattern, 0, -1, shouldIgnoreCase(pattern, ignoreCase));
|
||||
if (results.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final int size = EditorHelper.getFileSize(editor);
|
||||
results.sort((r1, r2) -> {
|
||||
final TextRange max = Collections.max(results, (r1, r2) -> {
|
||||
final int d1 = distance(r1, offset, forwards, size);
|
||||
final int d2 = distance(r2, offset, forwards, size);
|
||||
if (d1 < 0 && d2 >= 0) {
|
||||
return Integer.MIN_VALUE;
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
return d1 - d2;
|
||||
return d2 - d1;
|
||||
});
|
||||
TextRange nThClosest = results.get((count - 1) % results.size());
|
||||
if (!Options.getInstance().isSet("wrapscan")) {
|
||||
final int start = nThClosest.getStartOffset();
|
||||
final int start = max.getStartOffset();
|
||||
if (forwards && start < offset) {
|
||||
return null;
|
||||
}
|
||||
@ -669,51 +644,32 @@ public class SearchGroup {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return nThClosest;
|
||||
return max;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static TextRange findNextSearch(@NotNull Editor editor, int count, boolean forwards) {
|
||||
String lastSearch = VimPlugin.getSearch().getLastSearch();
|
||||
if (lastSearch == null) return null;
|
||||
|
||||
int currentPos = editor.getCaretModel().getOffset();
|
||||
TextRange nextRange = new TextRange(currentPos, currentPos);
|
||||
int startOffset = nextRange.getStartOffset();
|
||||
nextRange = findNext(editor, lastSearch, startOffset - 1, false, forwards);
|
||||
if (nextRange == null) {
|
||||
return null;
|
||||
public TextRange findNextSearchForGn(@NotNull Editor editor, int count, boolean forwards) {
|
||||
if (forwards) {
|
||||
return findIt(editor, editor.getCaretModel().getOffset(), count, 1, false, true, false, true);
|
||||
} else {
|
||||
return searchBackward(editor, editor.getCaretModel().getOffset(), count);
|
||||
}
|
||||
return findNext(editor, lastSearch, nextRange, forwards, count - 1);
|
||||
}
|
||||
|
||||
public TextRange findUnderCaret(@NotNull Editor editor) {
|
||||
final TextRange backSearch = searchBackward(editor, editor.getCaretModel().getOffset() + 1, 1);
|
||||
if (backSearch == null) return null;
|
||||
return backSearch.contains(editor.getCaretModel().getOffset()) ? backSearch : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static TextRange findCurrentOrNextSearch(@NotNull Editor editor, int count, boolean forwards) {
|
||||
String lastSearch = VimPlugin.getSearch().getLastSearch();
|
||||
if (lastSearch == null) return null;
|
||||
|
||||
int currentPos = editor.getCaretModel().getOffset();
|
||||
TextRange nextRange = new TextRange(currentPos, currentPos);
|
||||
int startOffset = nextRange.getStartOffset();
|
||||
nextRange =
|
||||
findCurrent(editor, lastSearch, startOffset).orElse(findNext(editor, lastSearch, startOffset, false, forwards));
|
||||
if (nextRange == null) {
|
||||
return null;
|
||||
}
|
||||
return findNext(editor, lastSearch, nextRange, forwards, count - 1);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static TextRange findNext(@NotNull Editor editor,
|
||||
@NotNull String lastSearch,
|
||||
@NotNull TextRange nextRange,
|
||||
boolean forwards,
|
||||
int count) {
|
||||
if (count <= 0) {
|
||||
return nextRange;
|
||||
}
|
||||
return findNext(editor, lastSearch, Math.max(nextRange.getStartOffset() - (forwards ? 0 : 1), 0), false, forwards,
|
||||
count);
|
||||
private TextRange searchBackward(@NotNull Editor editor, int offset, int count) {
|
||||
// Backward search returns wrongs end offset for some cases. That's why we should perform additional forward search
|
||||
final TextRange foundBackward = findIt(editor, offset, count, -1, false, true, false, true);
|
||||
if (foundBackward == null) return null;
|
||||
int startOffset = foundBackward.getStartOffset() - 1;
|
||||
if (startOffset < 0) startOffset = EditorHelper.getFileSize(editor);
|
||||
return findIt(editor, startOffset, 1, 1, false, true, false, true);
|
||||
}
|
||||
|
||||
private static int distance(@NotNull TextRange range, int pos, boolean forwards, int size) {
|
||||
@ -888,10 +844,8 @@ public class SearchGroup {
|
||||
@Nullable
|
||||
private TextRange findIt(@NotNull Editor editor, int startOffset, int count, int dir,
|
||||
boolean noSmartCase, boolean wrap, boolean showMessages, boolean wholeFile) {
|
||||
TextRange res = null;
|
||||
|
||||
if (lastSearch == null || lastSearch.length() == 0) {
|
||||
return res;
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -907,10 +861,6 @@ public class SearchGroup {
|
||||
regmatch.rmm_ic = shouldIgnoreCase(lastSearch, noSmartCase);
|
||||
sp = new RegExp();
|
||||
regmatch.regprog = sp.vim_regcomp(lastSearch, 1);
|
||||
if (regmatch == null) {
|
||||
if (logger.isDebugEnabled()) logger.debug("bad pattern: " + lastSearch);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
int extra_col = 1;
|
||||
|
@ -1,10 +1,31 @@
|
||||
/*
|
||||
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
|
||||
* Copyright (C) 2003-2019 The IdeaVim authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.jetbrains.plugins.ideavim.gn;
|
||||
|
||||
import com.maddyhome.idea.vim.VimPlugin;
|
||||
import com.maddyhome.idea.vim.command.CommandFlags;
|
||||
import com.maddyhome.idea.vim.command.CommandState;
|
||||
import org.jetbrains.plugins.ideavim.VimTestCase;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import static com.maddyhome.idea.vim.helper.StringHelper.parseKeys;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
|
||||
public class VisualSelectNextSearchTest extends VimTestCase {
|
||||
public void testSearch() {
|
||||
@ -15,6 +36,24 @@ public class VisualSelectNextSearchTest extends VimTestCase {
|
||||
assertMode(CommandState.Mode.VISUAL);
|
||||
}
|
||||
|
||||
public void testSearchFordAndBack() {
|
||||
typeTextInFile(parseKeys("*", "2b", "gn", "gN"), "h<caret>ello world\nhello world hello world");
|
||||
|
||||
assertOffset(0);
|
||||
assertSelection("h");
|
||||
assertMode(CommandState.Mode.VISUAL);
|
||||
}
|
||||
|
||||
public void testWithoutSpaces() {
|
||||
configureByText("test<caret>test");
|
||||
VimPlugin.getSearch().search(myFixture.getEditor(), "test", 1, EnumSet.noneOf(CommandFlags.class), false);
|
||||
typeText(parseKeys("gn"));
|
||||
|
||||
assertOffset(7);
|
||||
assertSelection("test");
|
||||
assertMode(CommandState.Mode.VISUAL);
|
||||
}
|
||||
|
||||
public void testSearchCurrentlyInOne() {
|
||||
typeTextInFile(parseKeys("*", "gn"), "h<caret>ello world\nhello world hello world");
|
||||
|
||||
@ -30,6 +69,13 @@ public class VisualSelectNextSearchTest extends VimTestCase {
|
||||
assertSelection("hello");
|
||||
}
|
||||
|
||||
public void testSearchTwiceInVisual() {
|
||||
typeTextInFile(parseKeys("*", "gn", "2gn"), "h<caret>ello world\nhello world hello, hello hello");
|
||||
|
||||
assertOffset(35);
|
||||
assertSelection("hello world hello, hello");
|
||||
}
|
||||
|
||||
public void testTwoSearchesStayInVisualMode() {
|
||||
typeTextInFile(parseKeys("*", "gn", "gn"), "h<caret>ello world\nhello world hello, hello");
|
||||
|
||||
|
@ -1,8 +1,30 @@
|
||||
/*
|
||||
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
|
||||
* Copyright (C) 2003-2019 The IdeaVim authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.jetbrains.plugins.ideavim.gn;
|
||||
|
||||
import com.maddyhome.idea.vim.VimPlugin;
|
||||
import com.maddyhome.idea.vim.command.CommandFlags;
|
||||
import com.maddyhome.idea.vim.command.CommandState;
|
||||
import org.jetbrains.plugins.ideavim.VimTestCase;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import static com.maddyhome.idea.vim.helper.StringHelper.parseKeys;
|
||||
|
||||
public class VisualSelectPreviousSearchTest extends VimTestCase {
|
||||
@ -24,6 +46,16 @@ public class VisualSelectPreviousSearchTest extends VimTestCase {
|
||||
assertMode(CommandState.Mode.VISUAL);
|
||||
}
|
||||
|
||||
public void testWithoutSpaces() {
|
||||
configureByText("tes<caret>ttest");
|
||||
VimPlugin.getSearch().search(myFixture.getEditor(), "test", 1, EnumSet.noneOf(CommandFlags.class), false);
|
||||
typeText(parseKeys("gN"));
|
||||
|
||||
assertOffset(0);
|
||||
assertSelection("test");
|
||||
assertMode(CommandState.Mode.VISUAL);
|
||||
}
|
||||
|
||||
public void testSearchTwice() {
|
||||
typeTextInFile(parseKeys("*", "2gN"), "hello world\nh<caret>ello world hello");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user