1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-03-04 21:32:52 +01:00

Support comments in brace matching

In Vim, '%' can be used to jump between the '/*' and '*/' of block
comments. Support this functionality in a language-independent manner.
This commit is contained in:
Tuomas Tynkkynen 2014-12-14 15:19:26 +02:00
parent 3650ab85df
commit 82a9587b4f
4 changed files with 145 additions and 2 deletions
src/com/maddyhome/idea/vim/helper
test/org/jetbrains/plugins/ideavim

View File

@ -109,7 +109,7 @@ public class PsiHelper {
}
@Nullable
private static PsiFile getFile(@NotNull Editor editor) {
public static PsiFile getFile(@NotNull Editor editor) {
VirtualFile vf = EditorData.getVirtualFile(editor);
if (vf != null) {
Project proj = editor.getProject();

View File

@ -18,9 +18,14 @@
package com.maddyhome.idea.vim.helper;
import com.intellij.lang.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.*;
import com.maddyhome.idea.vim.common.TextRange;
import com.maddyhome.idea.vim.option.ListOption;
import com.maddyhome.idea.vim.option.OptionChangeEvent;
@ -143,6 +148,54 @@ public class SearchHelper {
return new TextRange(bstart, bend);
}
private static int findMatchingBlockCommentPair(@NotNull PsiElement element,
int pos,
@Nullable String commentPrefix,
@Nullable String commentSuffix) {
if (commentPrefix == null || commentSuffix == null) {
return -1;
}
// Don't act on partial comments
if (!element.getText().startsWith(commentPrefix) || !element.getText().endsWith(commentSuffix)) {
return -1;
}
final int endOffset = element.getTextOffset() + element.getTextLength();
if (pos < element.getTextOffset() + commentPrefix.length()) {
return endOffset;
}
else if (pos >= endOffset - commentSuffix.length()) {
return element.getTextOffset();
}
return -1;
}
private static int findMatchingBlockCommentPair(PsiElement element, int pos) {
final Language language = PsiUtil.findLanguageFromElement(element);
final Commenter commenter = LanguageCommenters.INSTANCE.forLanguage(language);
element = PsiTreeUtil.getParentOfType(element, PsiComment.class, false);
if (element == null) {
return -1;
}
int ret = findMatchingBlockCommentPair(element, pos, commenter.getBlockCommentPrefix(),
commenter.getBlockCommentSuffix());
if (ret >= 0) {
return ret;
}
if (!(commenter instanceof CodeDocumentationAwareCommenter)) {
return -1;
}
final CodeDocumentationAwareCommenter docCommenter = (CodeDocumentationAwareCommenter)commenter;
return findMatchingBlockCommentPair(element, pos, docCommenter.getDocumentationCommentPrefix(),
docCommenter.getDocumentationCommentSuffix());
}
/**
* This looks on the current line, starting at the cursor position for one of {, }, (, ), [, or ]. It then searches
* forward or backward, as appropriate for the associated match pair. String in double quotes are skipped over.
@ -153,10 +206,23 @@ public class SearchHelper {
* were found on the remainder of the current line.
*/
public static int findMatchingPairOnCurrentLine(@NotNull Editor editor) {
int pos = editor.getCaretModel().getOffset();
// If on '/*' of a block comment, jump to '*/' of that comment, or vice versa
PsiFile psiFile = PsiHelper.getFile(editor);
if (psiFile != null) {
PsiElement element = psiFile.findElementAt(pos);
if (element != null) {
int ret = findMatchingBlockCommentPair(element, pos);
if (ret >= 0) {
return ret;
}
}
}
int line = editor.getCaretModel().getLogicalPosition().line;
int end = EditorHelper.getLineEndOffset(editor, line, true);
CharSequence chars = editor.getDocument().getCharsSequence();
int pos = editor.getCaretModel().getOffset();
int loc = -1;
// Search the remainder of the current line for one of the candidate characters
while (pos < end) {

View File

@ -1,6 +1,7 @@
package org.jetbrains.plugins.ideavim;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.ide.highlighter.XmlFileType;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Editor;
@ -90,6 +91,12 @@ public abstract class VimTestCase extends UsefulTestCase {
return myFixture.getEditor();
}
@NotNull
protected Editor configureByXmlText(@NotNull String content) {
myFixture.configureByText(XmlFileType.INSTANCE, content);
return myFixture.getEditor();
}
@NotNull
protected Editor typeText(@NotNull final List<KeyStroke> keys) {
final Editor editor = myFixture.getEditor();

View File

@ -426,6 +426,76 @@ public class MotionActionTest extends VimTestCase {
assertOffset(3);
}
// |%|
public void testPercentMatchXmlCommentStart() {
configureByXmlText("<caret><!-- foo -->");
typeText(parseKeys("%"));
assertOffset(11);
}
// |%|
public void testPercentDoesntMatchPartialXmlComment() {
configureByXmlText("<!<caret>-- ");
typeText(parseKeys("%"));
assertOffset(2);
}
// |%|
public void testPercentMatchXmlCommentEnd() {
configureByXmlText("<!-- foo --<caret>>");
typeText(parseKeys("%"));
assertOffset(0);
}
// |%|
public void testPercentMatchJavaCommentStart() {
configureByJavaText("/<caret>* foo */");
typeText(parseKeys("%"));
assertOffset(8);
}
// |%|
public void testPercentDoesntMatchPartialJavaComment() {
configureByJavaText("<caret>/* ");
typeText(parseKeys("%"));
assertOffset(0);
}
// |%|
public void testPercentMatchJavaCommentEnd() {
configureByJavaText("/* foo <caret>*/");
typeText(parseKeys("%"));
assertOffset(0);
}
// |%|
public void testPercentMatchJavaDocCommentStart() {
configureByJavaText("/*<caret>* foo */");
typeText(parseKeys("%"));
assertOffset(9);
}
// |%|
public void testPercentMatchJavaDocCommentEnd() {
configureByJavaText("/** foo *<caret>/");
typeText(parseKeys("%"));
assertOffset(0);
}
// |%|
public void testPercentDoesntMatchAfterCommentStart() {
configureByJavaText("/*<caret> foo */");
typeText(parseKeys("%"));
assertOffset(2);
}
// |%|
public void testPercentDoesntMatchBeforeCommentEnd() {
configureByJavaText("/* foo <caret> */");
typeText(parseKeys("%"));
assertOffset(7);
}
// |[(|
public void testUnmatchedOpenParenthesis() {
typeTextInFile(parseKeys("[("),