1
0
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:
Alex Plate 2019-06-11 11:49:59 +03:00
parent b795c62ab7
commit eeea093bb8
No known key found for this signature in database
GPG Key ID: 0B97153C8FFEC09F
4 changed files with 124 additions and 100 deletions
src/com/maddyhome/idea/vim/group
test/org/jetbrains/plugins/ideavim/gn

View File

@ -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;

View File

@ -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;

View File

@ -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");

View File

@ -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");