mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-04-15 17:15:43 +02:00
Support gn text objects
This commit is contained in:
parent
e919a026b7
commit
778ddb0e75
resources/META-INF
src/com/maddyhome/idea/vim
test/org/jetbrains/plugins/ideavim/action/motion/gn
@ -419,5 +419,7 @@
|
||||
<!-- Visual Selection of last Search Pattern (gn) -->
|
||||
<action id="VimVisualSelectNextSearch" class="com.maddyhome.idea.vim.action.motion.gn.VisualSelectNextSearch" text="Visual Select Next Search"/>
|
||||
<action id="VimVisualSelectPreviousSearch" class="com.maddyhome.idea.vim.action.motion.gn.VisualSelectPreviousSearch" text="Visual Select Previous Search"/>
|
||||
<action id="VimGnNextTextObject" class="com.maddyhome.idea.vim.action.motion.gn.GnNextTextObject" text="Gn Next Text Object"/>
|
||||
<action id="VimGnPreviousTextObject" class="com.maddyhome.idea.vim.action.motion.gn.GnPreviousTextObject" text="Gn Previous Text Object"/>
|
||||
</actions>
|
||||
</idea-plugin>
|
||||
|
@ -179,6 +179,14 @@ class RegisterActions {
|
||||
EnumSet.of(CommandFlags.FLAG_MOT_CHARACTERWISE, CommandFlags.FLAG_MOT_INCLUSIVE, CommandFlags.FLAG_TEXT_BLOCK),
|
||||
new Shortcut[]{new Shortcut("at")}
|
||||
);
|
||||
parser.registerAction(MappingMode.O, "VimGnNextTextObject", Command.Type.MOTION,
|
||||
EnumSet.of(CommandFlags.FLAG_MOT_CHARACTERWISE, CommandFlags.FLAG_MOT_INCLUSIVE),
|
||||
new Shortcut[]{new Shortcut("gn")}
|
||||
);
|
||||
parser.registerAction(MappingMode.O, "VimGnPreviousTextObject", Command.Type.MOTION,
|
||||
EnumSet.of(CommandFlags.FLAG_MOT_CHARACTERWISE, CommandFlags.FLAG_MOT_INCLUSIVE),
|
||||
new Shortcut[]{new Shortcut("gN")}
|
||||
);
|
||||
parser.registerAction(MappingMode.NO, "VimResetMode", Command.Type.RESET, new Shortcut(new KeyStroke[]{
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SLASH, KeyEvent.CTRL_MASK),
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_MASK)
|
||||
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 com.maddyhome.idea.vim.action.motion.gn
|
||||
|
||||
import com.intellij.openapi.actionSystem.DataContext
|
||||
import com.intellij.openapi.editor.Caret
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.maddyhome.idea.vim.VimPlugin
|
||||
import com.maddyhome.idea.vim.action.motion.TextObjectAction
|
||||
import com.maddyhome.idea.vim.command.Argument
|
||||
import com.maddyhome.idea.vim.common.TextRange
|
||||
import com.maddyhome.idea.vim.handler.TextObjectActionHandler
|
||||
|
||||
/**
|
||||
* @author Alex Plate
|
||||
*/
|
||||
|
||||
private object GnNextTextObjectHandler : TextObjectActionHandler() {
|
||||
override fun getRange(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): TextRange? {
|
||||
val range = VimPlugin.getSearch().getNextSearchRange(editor, count, true)
|
||||
val adj = VimPlugin.getVisualMotion().selectionAdj
|
||||
return range?.let { TextRange(it.startOffset, it.endOffset - adj) }
|
||||
}
|
||||
}
|
||||
|
||||
class GnNextTextObject : TextObjectAction(GnNextTextObjectHandler)
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 com.maddyhome.idea.vim.action.motion.gn
|
||||
|
||||
import com.intellij.openapi.actionSystem.DataContext
|
||||
import com.intellij.openapi.editor.Caret
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.maddyhome.idea.vim.VimPlugin
|
||||
import com.maddyhome.idea.vim.action.motion.TextObjectAction
|
||||
import com.maddyhome.idea.vim.command.Argument
|
||||
import com.maddyhome.idea.vim.common.TextRange
|
||||
import com.maddyhome.idea.vim.handler.TextObjectActionHandler
|
||||
|
||||
/**
|
||||
* @author Alex Plate
|
||||
*/
|
||||
|
||||
private object GnPreviousTextObjectHandler : TextObjectActionHandler() {
|
||||
override fun getRange(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): TextRange? {
|
||||
val range = VimPlugin.getSearch().getNextSearchRange(editor, count, false)
|
||||
val adj = VimPlugin.getVisualMotion().selectionAdj
|
||||
return range?.let { TextRange(it.startOffset, it.endOffset - adj) }
|
||||
}
|
||||
}
|
||||
|
||||
class GnPreviousTextObject : TextObjectAction(GnPreviousTextObjectHandler)
|
@ -1352,44 +1352,16 @@ public class MotionGroup {
|
||||
}
|
||||
|
||||
public int selectNextSearch(@NotNull Editor editor, int count, boolean forwards) {
|
||||
editor.getCaretModel().removeSecondaryCarets();
|
||||
TextRange current = VimPlugin.getSearch().findUnderCaret(editor);
|
||||
final Caret caret = editor.getCaretModel().getPrimaryCaret();
|
||||
|
||||
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 TextRange range = VimPlugin.getSearch().getNextSearchRange(editor, count, forwards);
|
||||
if (range == null) return -1;
|
||||
final int adj = VimPlugin.getVisualMotion().getSelectionAdj();
|
||||
if (!CommandStateHelper.inVisualMode(editor)) {
|
||||
MotionGroup.moveCaret(editor, caret, gnStartOffset(current, forwards));
|
||||
final int startOffset = forwards ? range.getStartOffset() : Math.max(range.getEndOffset() - adj, 0);
|
||||
MotionGroup.moveCaret(editor, caret, startOffset);
|
||||
VimPlugin.getVisualMotion().enterVisualMode(editor, CommandState.SubMode.VISUAL_CHARACTER);
|
||||
}
|
||||
return gnEndOffset(current, forwards);
|
||||
}
|
||||
|
||||
private boolean atEdgeOfGnRange(@NotNull TextRange nextRange, @NotNull Editor editor, boolean forwards) {
|
||||
int currentPosition = editor.getCaretModel().getOffset();
|
||||
if (forwards) {
|
||||
return nextRange.getEndOffset() - 1 == currentPosition;
|
||||
}
|
||||
else {
|
||||
return nextRange.getStartOffset() == currentPosition;
|
||||
}
|
||||
}
|
||||
|
||||
private int gnEndOffset(@NotNull 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);
|
||||
return forwards ? Math.max(range.getEndOffset() - adj, 0) : range.getStartOffset();
|
||||
}
|
||||
|
||||
private int lastFTCmd = 0;
|
||||
|
@ -648,7 +648,31 @@ public class SearchGroup {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TextRange findNextSearchForGn(@NotNull Editor editor, int count, boolean forwards) {
|
||||
public TextRange getNextSearchRange(@NotNull Editor editor, int count, boolean forwards) {
|
||||
editor.getCaretModel().removeSecondaryCarets();
|
||||
TextRange current = findUnderCaret(editor);
|
||||
|
||||
if (current == null || CommandStateHelper.inVisualMode(editor) && atEdgeOfGnRange(current, editor, forwards)) {
|
||||
current = findNextSearchForGn(editor, count, forwards);
|
||||
}
|
||||
else if (count > 1) {
|
||||
current = findNextSearchForGn(editor, count - 1, forwards);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
private boolean atEdgeOfGnRange(@NotNull TextRange nextRange, @NotNull Editor editor, boolean forwards) {
|
||||
int currentPosition = editor.getCaretModel().getOffset();
|
||||
if (forwards) {
|
||||
return nextRange.getEndOffset() - VimPlugin.getVisualMotion().getSelectionAdj() == currentPosition;
|
||||
}
|
||||
else {
|
||||
return nextRange.getStartOffset() == currentPosition;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TextRange findNextSearchForGn(@NotNull Editor editor, int count, boolean forwards) {
|
||||
if (forwards) {
|
||||
return findIt(editor, editor.getCaretModel().getOffset(), count, 1, false, true, false, true);
|
||||
} else {
|
||||
@ -656,7 +680,8 @@ public class SearchGroup {
|
||||
}
|
||||
}
|
||||
|
||||
public TextRange findUnderCaret(@NotNull Editor editor) {
|
||||
@Nullable
|
||||
private 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;
|
||||
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@file:Suppress("RemoveCurlyBracesFromTemplate")
|
||||
|
||||
package org.jetbrains.plugins.ideavim.action.motion.gn
|
||||
|
||||
import com.maddyhome.idea.vim.VimPlugin
|
||||
import com.maddyhome.idea.vim.command.CommandFlags
|
||||
import com.maddyhome.idea.vim.command.CommandState
|
||||
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
|
||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||
import java.util.*
|
||||
import javax.swing.KeyStroke
|
||||
|
||||
class GnNextTextObjectTest : VimTestCase() {
|
||||
fun `test delete word`() {
|
||||
doTestWithSearch(parseKeys("dgn"), """
|
||||
Hello, ${c}this is a test here
|
||||
""".trimIndent(),
|
||||
"""
|
||||
Hello, this is a ${c} here
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test delete second word`() {
|
||||
doTestWithSearch(parseKeys("2dgn"), """
|
||||
Hello, ${c}this is a test here
|
||||
Hello, this is a test here
|
||||
""".trimIndent(),
|
||||
"""
|
||||
Hello, this is a test here
|
||||
Hello, this is a ${c} here
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test with repeat`() {
|
||||
doTestWithSearch(parseKeys("cgnNewValue<ESC>..."), """
|
||||
Hello, ${c}this is a test here
|
||||
Hello, this is a test here
|
||||
Hello, this is a test here
|
||||
Hello, this is a test here
|
||||
Hello, this is a test here
|
||||
""".trimIndent(),
|
||||
"""
|
||||
Hello, this is a NewValue here
|
||||
Hello, this is a NewValue here
|
||||
Hello, this is a NewValue here
|
||||
Hello, this is a NewValu${c}e here
|
||||
Hello, this is a test here
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
private fun doTestWithSearch(keys: List<KeyStroke>, before: String,
|
||||
after: String) {
|
||||
configureByText(before)
|
||||
VimPlugin.getSearch().search(myFixture.editor, "test", 1, EnumSet.noneOf(CommandFlags::class.java), false)
|
||||
typeText(keys)
|
||||
myFixture.checkResult(after)
|
||||
assertState(CommandState.Mode.COMMAND, CommandState.SubMode.NONE)
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@file:Suppress("RemoveCurlyBracesFromTemplate")
|
||||
|
||||
package org.jetbrains.plugins.ideavim.action.motion.gn
|
||||
|
||||
import com.maddyhome.idea.vim.VimPlugin
|
||||
import com.maddyhome.idea.vim.command.CommandFlags
|
||||
import com.maddyhome.idea.vim.command.CommandState
|
||||
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
|
||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||
import java.util.*
|
||||
import javax.swing.KeyStroke
|
||||
|
||||
class GnPreviousTextObjectTest : VimTestCase() {
|
||||
fun `test delete word`() {
|
||||
doTestWithSearch(parseKeys("dgN"), """
|
||||
Hello, ${c}this is a test here
|
||||
""".trimIndent(),
|
||||
"""
|
||||
Hello, this is a ${c} here
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test delete second word`() {
|
||||
doTestWithSearch(parseKeys("2dgN"), """
|
||||
Hello, this is a test here
|
||||
Hello, this is a test ${c}here
|
||||
""".trimIndent(),
|
||||
"""
|
||||
Hello, this is a ${c} here
|
||||
Hello, this is a test here
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
private fun doTestWithSearch(keys: List<KeyStroke>, before: String,
|
||||
after: String) {
|
||||
configureByText(before)
|
||||
VimPlugin.getSearch().search(myFixture.editor, "test", 1, EnumSet.noneOf(CommandFlags::class.java), false)
|
||||
typeText(keys)
|
||||
myFixture.checkResult(after)
|
||||
assertState(CommandState.Mode.COMMAND, CommandState.SubMode.NONE)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user