mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-08-18 10:31:44 +02:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
446ffc3602 | ||
![]() |
44c1a2e139 | ||
![]() |
f6cb04c7ef | ||
![]() |
276755ae9d | ||
![]() |
6ee0b821cc | ||
![]() |
72dc121fcd | ||
![]() |
786c4dc817 | ||
![]() |
c7cfbaed0a | ||
![]() |
4351d5c366 | ||
![]() |
ff3795798f | ||
![]() |
45281adfd9 | ||
![]() |
0d813afc67 |
14
CHANGES.md
14
CHANGES.md
@@ -3,6 +3,20 @@ The Changelog
|
||||
|
||||
History of changes in IdeaVim for the IntelliJ platform.
|
||||
|
||||
0.34, 2014-04-29
|
||||
----------------
|
||||
|
||||
A bugfix release.
|
||||
|
||||
Bug fixes:
|
||||
|
||||
* VIM-674 Don't handle `<Tab>` in Insert mode in Vim emulation
|
||||
* VIM-672 Ignore mappings that contain `<Plug>` and `<SID>`
|
||||
* VIM-670 First character of a recursive mapping shouldn't be mapped again
|
||||
* VIM-666 Support `<Bar>` in Vim key notation
|
||||
* VIM-666 Ignore characters after `|` in `:map` commands
|
||||
* VIM-667 Ignore potentially nested lines of .vimrc based on leading whitespace
|
||||
|
||||
|
||||
0.33, 2014-04-28
|
||||
----------------
|
||||
|
17
README.md
17
README.md
@@ -39,6 +39,10 @@ If you wish to disable the plugin, select the "Tools | Vim Emulator" menu so
|
||||
it is unchecked. At this point IDE will work with it's regular keyboard
|
||||
shortcuts.
|
||||
|
||||
Keyboard shortcut conflicts between the Vim emulation and the IDE can be
|
||||
resolved via "File | Settings | Vim Emulation", "File | Settings | Keymap"
|
||||
and key mapping commands in your ~/.ideavimrc or ~/.vimrc file.
|
||||
|
||||
|
||||
Summary of Supported Vim Features
|
||||
---------------------------------
|
||||
@@ -74,6 +78,19 @@ See also:
|
||||
* [Top features and bugs](http://youtrack.jetbrains.com/issues/VIM?q=%23Unresolved+sort+by%3A+votes)
|
||||
|
||||
|
||||
Files
|
||||
-----
|
||||
|
||||
* ~/.ideavimrc
|
||||
* Your IdeaVim-specific Vim initialization commands
|
||||
* ~/.vimrc
|
||||
* Your Vim initializations
|
||||
|
||||
Note, that IdeaVim currently parses .vimrc files via simple pattern matching,
|
||||
see [VIM-669](http://youtrack.jetbrains.com/issue/VIM-669) for proper parsing
|
||||
of VimL files.
|
||||
|
||||
|
||||
Changes to the IDE
|
||||
------------------
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
version-id:0.33
|
||||
version-id:0.34
|
||||
platform-version:120.0
|
||||
idea.download.url=http://download.jetbrains.com/idea/ideaIU-13.zip
|
||||
build.number=dev
|
||||
|
@@ -3,6 +3,10 @@
|
||||
<id>IdeaVIM</id>
|
||||
<change-notes>
|
||||
<![CDATA[
|
||||
<p>0.34:</p>
|
||||
<ul>
|
||||
<li>Various bug fixes</li>
|
||||
</ul>
|
||||
<p>0.33:</p>
|
||||
<ul>
|
||||
<li>Support for <code>:map</code> key mapping commands</li>
|
||||
@@ -25,12 +29,6 @@
|
||||
<li>Fixed long-standing issues with merged undo/redo commands and <code><Esc></code> during completion</li>
|
||||
<li>Various bug fixes</li>
|
||||
</ul>
|
||||
<p>0.29:</p>
|
||||
<ul>
|
||||
<li>Fixed repeat buffer limits</li>
|
||||
<li>Enable normal <code><Enter></code> handling for one-line editors</li>
|
||||
<li>Don't move cursor while scrolling</li>
|
||||
</ul>
|
||||
<p>See also the complete <a href="https://github.com/JetBrains/ideavim/blob/master/CHANGES.md">changelog</a>.</p>
|
||||
]]>
|
||||
</change-notes>
|
||||
|
@@ -252,8 +252,12 @@ public class KeyHandler {
|
||||
final Runnable handleMappedKeys = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final boolean fromIsPrefix = isPrefix(mappingInfo.getFromKeys(), mappingInfo.getToKeys());
|
||||
boolean first = true;
|
||||
for (KeyStroke keyStroke : mappingInfo.getToKeys()) {
|
||||
handleKey(editor, keyStroke, new EditorDataContext(editor), mappingInfo.isRecursive());
|
||||
final boolean recursive = mappingInfo.isRecursive() && !(first && fromIsPrefix);
|
||||
handleKey(editor, keyStroke, new EditorDataContext(editor), recursive);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -275,6 +279,18 @@ public class KeyHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> boolean isPrefix(@NotNull List<T> list1, @NotNull List<T> list2) {
|
||||
if (list1.size() > list2.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < list1.size(); i++) {
|
||||
if (!list1.get(i).equals(list2.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void handleEditorReset(@NotNull Editor editor, @NotNull KeyStroke key, @NotNull final DataContext context) {
|
||||
if (state != State.COMMAND && count == 0 && currentArg == Argument.Type.NONE && currentCmd.size() == 0 &&
|
||||
VimPlugin.getRegister().getCurrentRegister() == RegisterGroup.REGISTER_DEFAULT) {
|
||||
|
@@ -387,7 +387,7 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
|
||||
}
|
||||
}
|
||||
}
|
||||
if (previousStateVersion < 3) {
|
||||
if (previousStateVersion > 0 && previousStateVersion < 3) {
|
||||
final KeymapManagerEx manager = KeymapManagerEx.getInstanceEx();
|
||||
Keymap keymap = null;
|
||||
if (previousKeyMap != null) {
|
||||
@@ -404,7 +404,7 @@ public class VimPlugin implements ApplicationComponent, PersistentStateComponent
|
||||
"Switching to \"%s\" keymap.<br/><br/>" +
|
||||
"Now it is possible to set up:<br/>" +
|
||||
"<ul>" +
|
||||
"<li>Vim keys in your .vimrc file using key mapping commands</li>" +
|
||||
"<li>Vim keys in your .ideavimrc or .vimrc file using key mapping commands</li>" +
|
||||
"<li>IDE action shortcuts in \"File | Settings | Keymap\"</li>" +
|
||||
"<li>Vim or IDE handlers for conflicting shortcuts in <a href='#settings'>Vim Emulation</a> settings</li>" +
|
||||
"</ul>", keymap.getPresentableName()),
|
||||
|
@@ -139,7 +139,8 @@ public class VimShortcutKeyAction extends AnAction implements DumbAware {
|
||||
return isExitInsertMode(keyStroke);
|
||||
}
|
||||
if (CommandState.inInsertMode(editor)) {
|
||||
if (keyCode == VK_ENTER) {
|
||||
// XXX: <Enter> and <Tab> won't be recorded in macros
|
||||
if (keyCode == VK_ENTER || keyCode == VK_TAB) {
|
||||
return false;
|
||||
}
|
||||
// Debug watch, Python console, etc.
|
||||
|
@@ -55,7 +55,10 @@ public class VimScriptParser {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
try {
|
||||
line = line.trim();
|
||||
// TODO: Build a proper parse tree for a VimL file instead of ignoring potentially nested lines (VIM-669)
|
||||
if (line.startsWith(" ") || line.startsWith("\t")) {
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith(":")) {
|
||||
line = line.substring(1);
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@ package com.maddyhome.idea.vim.ex.handler;
|
||||
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.maddyhome.idea.vim.VimPlugin;
|
||||
import com.maddyhome.idea.vim.command.MappingMode;
|
||||
import com.maddyhome.idea.vim.ex.*;
|
||||
@@ -80,7 +81,13 @@ public class MapHandler extends CommandHandler implements VimScriptCommandHandle
|
||||
return editor != null && VimPlugin.getKey().showKeyMappings(modes, editor);
|
||||
}
|
||||
else {
|
||||
final CommandArguments arguments = parseCommandArguments(argument);
|
||||
final CommandArguments arguments;
|
||||
try {
|
||||
arguments = parseCommandArguments(argument);
|
||||
}
|
||||
catch (IllegalArgumentException ignored) {
|
||||
return false;
|
||||
}
|
||||
if (arguments != null) {
|
||||
for (SpecialArgument unsupportedArgument : UNSUPPORTED_SPECIAL_ARGUMENTS) {
|
||||
if (arguments.getSpecialArguments().contains(unsupportedArgument)) {
|
||||
@@ -99,6 +106,8 @@ public class MapHandler extends CommandHandler implements VimScriptCommandHandle
|
||||
|
||||
@Nullable
|
||||
private static CommandArguments parseCommandArguments(@NotNull String input) {
|
||||
input = getFirstBarSeparatedCommand(input);
|
||||
|
||||
final Set<SpecialArgument> specialArguments = new HashSet<SpecialArgument>();
|
||||
final StringBuilder toKeysBuilder = new StringBuilder();
|
||||
List<KeyStroke> fromKeys = null;
|
||||
@@ -117,14 +126,52 @@ public class MapHandler extends CommandHandler implements VimScriptCommandHandle
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = input.length() - 1; i >= 0; i--) {
|
||||
final char c = input.charAt(i);
|
||||
if (c == ' ') {
|
||||
toKeysBuilder.append(c);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fromKeys != null) {
|
||||
final List<KeyStroke> toKeys = parseKeys(toKeysBuilder.toString().trim());
|
||||
final List<KeyStroke> toKeys = parseKeys(StringUtil.trimLeading(toKeysBuilder.toString()));
|
||||
return new CommandArguments(specialArguments, fromKeys, toKeys);
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getFirstBarSeparatedCommand(@NotNull String input) {
|
||||
final StringBuilder inputBuilder = new StringBuilder();
|
||||
boolean escape = false;
|
||||
for (int i = 0; i < input.length(); i++) {
|
||||
final char c = input.charAt(i);
|
||||
if (escape) {
|
||||
escape = false;
|
||||
if (c != '|') {
|
||||
inputBuilder.append('\\');
|
||||
}
|
||||
inputBuilder.append(c);
|
||||
}
|
||||
else if (c == '\\') {
|
||||
escape = true;
|
||||
}
|
||||
else if (c == '|') {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
inputBuilder.append(c);
|
||||
}
|
||||
}
|
||||
if (input.endsWith("\\")) {
|
||||
inputBuilder.append("\\");
|
||||
}
|
||||
return inputBuilder.toString();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static CommandInfo getCommandInfo(@NotNull String command) {
|
||||
for (CommandInfo commandInfo : COMMAND_INFOS) {
|
||||
|
@@ -69,6 +69,12 @@ public class StringHelper {
|
||||
.build();
|
||||
private static final Map<Integer, String> VIM_KEY_VALUES = invertMap(VIM_KEY_NAMES);
|
||||
|
||||
private static final Map<String, Character> VIM_TYPED_KEY_NAMES = ImmutableMap.<String, Character>builder()
|
||||
.put("leader", '\\')
|
||||
.put("space", ' ')
|
||||
.put("bar", '|')
|
||||
.build();
|
||||
|
||||
private static final Set<String> UPPERCASE_DISPLAY_KEY_NAMES = ImmutableSet.<String>builder()
|
||||
.add("cr")
|
||||
.add("bs")
|
||||
@@ -146,9 +152,11 @@ public class StringHelper {
|
||||
ESCAPE,
|
||||
SPECIAL,
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses Vim key notation strings.
|
||||
*
|
||||
* @throws java.lang.IllegalArgumentException if the mapping doesn't make sense for Vim emulation
|
||||
* @see :help <>
|
||||
*/
|
||||
@NotNull
|
||||
@@ -186,7 +194,11 @@ public class StringHelper {
|
||||
if (c == '>') {
|
||||
state = KeyParserState.INIT;
|
||||
final String specialKeyName = specialKeyBuilder.toString();
|
||||
if (!"nop".equals(specialKeyName.toLowerCase())) {
|
||||
final String lower = specialKeyName.toLowerCase();
|
||||
if ("plug".equals(lower) || "sid".equals(lower)) {
|
||||
throw new IllegalArgumentException("<" + specialKeyName + "> is not supported");
|
||||
}
|
||||
if (!"nop".equals(lower)) {
|
||||
final KeyStroke specialKey = parseSpecialKey(specialKeyName, 0);
|
||||
if (specialKey != null) {
|
||||
result.add(specialKey);
|
||||
@@ -362,14 +374,12 @@ public class StringHelper {
|
||||
private static KeyStroke parseSpecialKey(@NotNull String s, int modifiers) {
|
||||
final String lower = s.toLowerCase();
|
||||
final Integer keyCode = VIM_KEY_NAMES.get(lower);
|
||||
final Character typedChar = VIM_TYPED_KEY_NAMES.get(lower);
|
||||
if (keyCode != null) {
|
||||
return getKeyStroke(keyCode, modifiers);
|
||||
}
|
||||
else if (lower.equals("leader")) {
|
||||
return getTypedOrPressedKeyStroke('\\', modifiers);
|
||||
}
|
||||
else if (lower.equals("space")) {
|
||||
return getTypedOrPressedKeyStroke(' ', modifiers);
|
||||
else if (typedChar != null) {
|
||||
return getTypedOrPressedKeyStroke(typedChar, modifiers);
|
||||
}
|
||||
else if (lower.startsWith(META_PREFIX)) {
|
||||
return parseSpecialKey(s.substring(META_PREFIX.length()), modifiers | META_MASK);
|
||||
|
@@ -159,4 +159,45 @@ public class MapCommandTest extends VimTestCase {
|
||||
typeText(parseKeys("dt,"));
|
||||
myFixture.checkResult(", bar\n");
|
||||
}
|
||||
|
||||
// VIM-666 |:imap|
|
||||
public void testIgnoreEverythingAfterBar() {
|
||||
configureByText("<caret>foo\n");
|
||||
typeText(commandToKeys("imap a b |c \" Something else"));
|
||||
typeText(parseKeys("ia"));
|
||||
myFixture.checkResult("b foo\n");
|
||||
}
|
||||
|
||||
// VIM-666 |:imap|
|
||||
public void testBarEscaped() {
|
||||
configureByText("<caret>foo\n");
|
||||
typeText(commandToKeys("imap a b \\| c"));
|
||||
typeText(parseKeys("ia"));
|
||||
myFixture.checkResult("b | cfoo\n");
|
||||
}
|
||||
|
||||
// VIM-666 |:imap|
|
||||
public void testBarEscapedSeveralSpaces() {
|
||||
configureByText("<caret>foo\n");
|
||||
typeText(commandToKeys("imap a b \\| c |"));
|
||||
typeText(parseKeys("ia"));
|
||||
myFixture.checkResult("b | c foo\n");
|
||||
}
|
||||
|
||||
// VIM-670 |:map|
|
||||
public void testFirstCharIsNonRecursive() {
|
||||
configureByText("\n");
|
||||
typeText(commandToKeys("map ab abcd"));
|
||||
typeText(parseKeys("ab"));
|
||||
myFixture.checkResult("bcd\n");
|
||||
}
|
||||
|
||||
// VIM-672 |:map|
|
||||
public void testIgnorePlugMappings() {
|
||||
configureByText("<caret>foo bar\n");
|
||||
typeText(commandToKeys("map w <Plug>abc"));
|
||||
typeText(parseKeys("w"));
|
||||
myFixture.checkResult("foo bar\n");
|
||||
assertOffset(4);
|
||||
}
|
||||
}
|
||||
|
@@ -64,6 +64,11 @@ public class StringHelperTest extends TestCase {
|
||||
assertPressedKeyStroke("BACK_SPACE", "<Backspace>");
|
||||
}
|
||||
|
||||
// VIM-666
|
||||
public void testParseBarSpecialKey() {
|
||||
assertTypedKeyStroke('|', "<Bar>");
|
||||
}
|
||||
|
||||
private void assertPressedKeyStroke(@NotNull String expected, @NotNull String actual) {
|
||||
assertEquals(KeyStroke.getKeyStroke(expected), parseKeyStroke(actual));
|
||||
}
|
||||
|
Reference in New Issue
Block a user