diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpCompletionContributor.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpCompletionContributor.java index c7a9927ed7f7..0d37cef74aa8 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpCompletionContributor.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpCompletionContributor.java @@ -7,10 +7,15 @@ import com.intellij.codeInsight.lookup.MutableLookupElement; import com.intellij.patterns.ElementPattern; import static com.intellij.patterns.PlatformPatterns.psiElement; import com.intellij.psi.PsiElement; +import com.intellij.util.Icons; import com.intellij.util.ProcessingContext; +import com.intellij.util.ui.EmptyIcon; import org.intellij.lang.regexp.psi.impl.RegExpPropertyImpl; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import javax.swing.*; + /** * Created by IntelliJ IDEA. * User: vnikolaenko @@ -19,62 +24,98 @@ import org.jetbrains.annotations.NotNull; * To change this template use File | Settings | File Templates. */ public class RegExpCompletionContributor extends CompletionContributor { - public RegExpCompletionContributor() { - final ElementPattern backSlashPattern = psiElement().withText("\\\\"); - extend(CompletionType.BASIC, psiElement().afterLeaf(backSlashPattern), new CharacterClassesNameCompletionProvider()); + private static final Icon emptyIcon = new EmptyIcon(Icons.PROPERTY_ICON.getIconWidth(), Icons.PROPERTY_ICON.getIconHeight()); - final ElementPattern propertyPattern - = psiElement().withText("p").afterLeaf(backSlashPattern); - extend(CompletionType.BASIC, psiElement().afterLeaf(propertyPattern), new PropertyCompletionProvider()); + public RegExpCompletionContributor() { + { + extend(CompletionType.BASIC, psiElement().withText("\\I"), new CharacterClassesNameCompletionProvider()); - final ElementPattern propertyNamePattern - = psiElement().afterLeaf(psiElement().withText("{").afterLeaf(propertyPattern)); - extend(CompletionType.BASIC, propertyNamePattern, new PropertyNameCompletionProvider()); + final ElementPattern propertyPattern = psiElement().withText("\\p"); + extend(CompletionType.BASIC, psiElement().afterLeaf(propertyPattern), new PropertyCompletionProvider()); + + final ElementPattern propertyNamePattern = psiElement().afterLeaf(psiElement().withText("{").afterLeaf(propertyPattern)); + extend(CompletionType.BASIC, propertyNamePattern, new PropertyNameCompletionProvider()); } - private static MutableLookupElement addLookupElement(final CompletionResultSet result, - final String name) { - MutableLookupElement element = LookupElementFactory.getInstance().createLookupElement(name); - result.addElement(element); - return element; + { + // TODO: backSlashPattern is needed for reg exp in injected context, remove when unescaping will be performed by Injecting framework + final ElementPattern backSlashPattern = psiElement().withText("\\\\I"); + extend(CompletionType.BASIC, backSlashPattern, new CharacterClassesNameCompletionProvider()); + + final ElementPattern propertyPattern = psiElement().withText("\\\\p"); + extend(CompletionType.BASIC, psiElement().afterLeaf(propertyPattern), new PropertyCompletionProvider()); + + final ElementPattern propertyNamePattern + = psiElement().afterLeaf(psiElement().withText("{").afterLeaf(propertyPattern)); + extend(CompletionType.BASIC, propertyNamePattern, new PropertyNameCompletionProvider()); } - private static class PropertyNameCompletionProvider extends CompletionProvider { + { + // TODO: this seems to be needed only for tests! + final ElementPattern backSlashPattern = psiElement().withText("\\\\"); + extend(CompletionType.BASIC, psiElement().afterLeaf(backSlashPattern), new CharacterClassesNameCompletionProvider()); - public void addCompletions(@NotNull final CompletionParameters parameters, - final ProcessingContext context, - @NotNull final CompletionResultSet result) { - for (String[] stringArray : RegExpPropertyImpl.PROPERTY_NAMES) { - addLookupElement(result, stringArray[0]).setTailType(TailType.createSimpleTailType('}')); - } - } + final ElementPattern propertyPattern + = psiElement().withText("p").afterLeaf(backSlashPattern); + extend(CompletionType.BASIC, psiElement().afterLeaf(propertyPattern), new PropertyCompletionProvider()); + + final ElementPattern propertyNamePattern + = psiElement().afterLeaf(psiElement().withText("{").afterLeaf(propertyPattern)); + extend(CompletionType.BASIC, propertyNamePattern, new PropertyNameCompletionProvider()); } + } - private static class PropertyCompletionProvider extends CompletionProvider { + private static MutableLookupElement addLookupElement(final CompletionResultSet result, @NonNls final String name, String type, Icon icon) { + MutableLookupElement element = LookupElementFactory.getInstance().createLookupElement(name); + result.addElement(element); + if (type != null) element.setTypeText(type); + if (icon != null) element.setIcon(icon); - public void addCompletions(@NotNull final CompletionParameters parameters, - final ProcessingContext context, - @NotNull final CompletionResultSet result) { - for (String[] stringArray : RegExpPropertyImpl.PROPERTY_NAMES) { - addLookupElement(result, "{" + stringArray[0] + "}"); - } - } + return element; + } + + private static class PropertyNameCompletionProvider extends CompletionProvider { + + public void addCompletions(@NotNull final CompletionParameters parameters, + final ProcessingContext context, + @NotNull final CompletionResultSet result) { + for (String[] stringArray : RegExpPropertyImpl.PROPERTY_NAMES) { + addLookupElement(result, stringArray[0], null, emptyIcon).setTailType(TailType.createSimpleTailType('}')); + } } - private static class CharacterClassesNameCompletionProvider extends CompletionProvider { + } - public void addCompletions(@NotNull final CompletionParameters parameters, - final ProcessingContext context, - @NotNull final CompletionResultSet result) { - String[] completions = { - "d", "D", "s", "S", "w", "W", "b", "B", "A", "G", "Z", "z", "Q", "E", - "t", "n", "r", "f", "a", "e" - }; - for (String s : completions) { - addLookupElement(result, s); - } - for (String[] stringArray : RegExpPropertyImpl.PROPERTY_NAMES) { - addLookupElement(result, "p{" + stringArray[0] + "}"); - } - } + private static class PropertyCompletionProvider extends CompletionProvider { + + public void addCompletions(@NotNull final CompletionParameters parameters, + final ProcessingContext context, + @NotNull final CompletionResultSet result) { + for (String[] stringArray : RegExpPropertyImpl.PROPERTY_NAMES) { + addLookupElement(result, "{" + stringArray[0] + "}", stringArray.length > 1 ? stringArray[1]:null, Icons.PROPERTY_ICON); + } } + } + + private static class CharacterClassesNameCompletionProvider extends CompletionProvider { + + public void addCompletions(@NotNull final CompletionParameters parameters, + final ProcessingContext context, + @NotNull final CompletionResultSet result) { + @NonNls String[] completions = {"d", "D", "s", "S", "w", "W", "b", "B", "A", "G", "Z", "z", "Q", "E", "t", "n", "r", "f", "a", "e"}; + @NonNls String[] completionsTypes = {"digit: [0-9]", "nondigit: [^0-9]", "whitespace [ \\t\\n\\x0B\\f\\r]", "non-whitespace [^\\s]", + "word character [a-zA-Z_0-9]", "nonword character [^\\w]", "word boundary", "non-word boundary", "beginning of the input", + "end of the previous match", "end of the input but for the final terminator, if any", "end of input", + "Nothing, but quotes all characters until \\E", " \tNothing, but ends quoting started by \\Q", "tab character ('\\u0009')", + "newline (line feed) character ('\\u000A')", "carriage-return character ('\\u000D')", "form-feed character ('\\u000C')", + "alert (bell) character ('\\u0007')", "escape character ('\\u001B')"}; + + for (int i = 0; i < completions.length; ++i) { + addLookupElement(result, completions[i], completionsTypes[i], emptyIcon); + } + + for (String[] stringArray : RegExpPropertyImpl.PROPERTY_NAMES) { + addLookupElement(result, "p{" + stringArray[0] + "}", stringArray.length > 1? stringArray[1]:null, Icons.PROPERTY_ICON); + } + } + } } diff --git a/RegExpSupport/test/test/RegExpCompletionTest.java b/RegExpSupport/test/test/RegExpCompletionTest.java index 6cf24eeb6e04..32268f4b6a72 100644 --- a/RegExpSupport/test/test/RegExpCompletionTest.java +++ b/RegExpSupport/test/test/RegExpCompletionTest.java @@ -24,6 +24,14 @@ public class RegExpCompletionTest extends CodeInsightFixtureTestCase { } public void testBackSlashVariants() throws Throwable { + doBackSlashVariantsTest(); + } + + public void testBackSlashVariants2() throws Throwable { + doBackSlashVariantsTest(); + } + + private void doBackSlashVariantsTest() throws Throwable { java.util.List nameList = new ArrayList(Arrays.asList("d", "D", "s", "S", "w", "W", "b", "B", "A", "G", "Z", "z", "Q", "E", "t", "n", "r", "f", "a", "e")); for (String[] stringArray : RegExpPropertyImpl.PROPERTY_NAMES) { @@ -32,7 +40,7 @@ public class RegExpCompletionTest extends CodeInsightFixtureTestCase { myFixture.testCompletionVariants(getInputDataFileName(getTestName(true)), nameList.toArray(new String[nameList.size()])); } - public void testPropertyVariants() throws Throwable { + public void testPropertyVariants() throws Throwable { java.util.List nameList = new ArrayList(); for (String[] stringArray : RegExpPropertyImpl.PROPERTY_NAMES) { nameList.add("{" + stringArray[0] + "}"); diff --git a/RegExpSupport/testData/completion/BackSlashVariants2.regexp b/RegExpSupport/testData/completion/BackSlashVariants2.regexp new file mode 100644 index 000000000000..eb047c06c06f --- /dev/null +++ b/RegExpSupport/testData/completion/BackSlashVariants2.regexp @@ -0,0 +1 @@ +[0-9]\