diff --git a/compiler/frontend/src/org/jetbrains/jet/lexer/JetKeywordToken.java b/compiler/frontend/src/org/jetbrains/jet/lexer/JetKeywordToken.java
index cc3c35dd1f7..920fd65766b 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lexer/JetKeywordToken.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lexer/JetKeywordToken.java
@@ -8,10 +8,16 @@ import org.jetbrains.annotations.NotNull;
public class JetKeywordToken extends JetToken {
+ /**
+ * Generate soft keyword (identifier that has a keyword meaning only in some contexts)
+ */
public static JetKeywordToken keyword(String value) {
return new JetKeywordToken(value, false);
}
+ /**
+ * Generate keyword (identifier that has a keyword meaning in all possible contexts)
+ */
public static JetKeywordToken softKeyword(String value) {
return new JetKeywordToken(value, true);
}
@@ -29,6 +35,7 @@ public class JetKeywordToken extends JetToken {
return myValue;
}
+
public boolean isSoft() {
return myIsSoft;
}
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 3c218cee23f..472e7e9f54e 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -42,6 +42,7 @@
+
@@ -57,6 +58,7 @@
+
{
+
+ private final static String[] COMPLETE_KEYWORD = new String[] {
+ "namespace", "as", "type", "class", "this", "super", "val", "var", "fun", "for", "null", "true",
+ "false", "is", "in", "throw", "return", "break", "continue", "object", "if", "try", "else", "while",
+ "do", "when", "trait", "This"
+ };
+
+ private final static String[] COMPLETE_SOFT_KEYWORDS = new String[] {
+ "import", "where", "by", "get", "set", "abstract", "enum", "open", "annotation", "override", "private",
+ "public", "internal", "protected", "catch", "out", "vararg", "inline", "finally", "final", "ref"
+ };
+
+ @Override
+ protected void addCompletions(@NotNull CompletionParameters parameters,
+ ProcessingContext context,
+ @NotNull CompletionResultSet result) {
+
+ for (String keyword : COMPLETE_KEYWORD) {
+ result.addElement(LookupElementBuilder.create(keyword).setBold());
+ }
+
+ for (String softKeyword : COMPLETE_SOFT_KEYWORDS) {
+ result.addElement(LookupElementBuilder.create(softKeyword));
+ }
+ }
+ }
+
+ public JetKeywordCompletionContributor() {
+ extend(CompletionType.BASIC, PlatformPatterns.psiElement(), new JetKeywordCompletionProvider());
+ }
+}
diff --git a/idea/testData/completion/keywords/InFunctionScope.kt b/idea/testData/completion/keywords/InFunctionScope.kt
new file mode 100644
index 00000000000..c59f322f1a8
--- /dev/null
+++ b/idea/testData/completion/keywords/InFunctionScope.kt
@@ -0,0 +1,5 @@
+fun foo() {
+
+}
+
+// EXIST: val, var
diff --git a/idea/testData/completion/keywords/InTypeScope.kt b/idea/testData/completion/keywords/InTypeScope.kt
new file mode 100644
index 00000000000..31f2249d499
--- /dev/null
+++ b/idea/testData/completion/keywords/InTypeScope.kt
@@ -0,0 +1,6 @@
+fun foo() {
+ val test :
+}
+
+// TODO: Move all keywords to absent
+// EXPECT: fun, val, var, namespace
diff --git a/idea/testData/completion/keywords/TopScope.kt b/idea/testData/completion/keywords/TopScope.kt
new file mode 100644
index 00000000000..a151d11e196
--- /dev/null
+++ b/idea/testData/completion/keywords/TopScope.kt
@@ -0,0 +1,8 @@
+
+
+// EXPECT: namespace, as, type, class, this, super, val, var, fun, for, null, true
+// EXPECT: false, is, in, throw, return, break, continue, object, if, try, else, while
+// EXPECT: do, when, trait, This
+// EXPECT: import, where, by, get, set, abstract, enum, open, annotation, override, private
+// EXPECT: public, internal, protected, catch, out, vararg, inline, finally, final, ref
+// ABSENT: ?in, new, extends, implements
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/jet/completion/JetCompletionTestBase.java b/idea/tests/org/jetbrains/jet/completion/JetCompletionTestBase.java
new file mode 100644
index 00000000000..c0ff4263210
--- /dev/null
+++ b/idea/tests/org/jetbrains/jet/completion/JetCompletionTestBase.java
@@ -0,0 +1,115 @@
+package org.jetbrains.jet.completion;
+
+import com.intellij.codeInsight.completion.CodeCompletionHandlerBase;
+import com.intellij.codeInsight.completion.CompletionType;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupEx;
+import com.intellij.codeInsight.lookup.LookupManager;
+import com.intellij.testFramework.LightCodeInsightTestCase;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * @author Nikolay.Krasko
+ */
+public abstract class JetCompletionTestBase extends LightCodeInsightTestCase {
+
+ protected void doTest() {
+ final String testName = getTestName(false);
+ configureByFile(testName + ".kt");
+
+ CompletionType completionType = (testName.startsWith("Smart")) ? CompletionType.SMART : CompletionType.BASIC;
+ new CodeCompletionHandlerBase(completionType, false, false, true).invokeCompletion(getProject(), getEditor());
+
+ LookupEx lookup = LookupManager.getActiveLookup(getEditor());
+ assert lookup != null;
+
+ HashSet items = new HashSet(resolveLookups(lookup.getItems()));
+
+ List shouldExist = itemsShouldExist(getFile().getText());
+ for (String shouldExistItem : shouldExist) {
+ assertTrue(String.format("Should contain proposal '%s'.", shouldExistItem),
+ items.contains(shouldExistItem));
+ }
+
+ List shouldAbsent = itemsShouldAbsent(getFile().getText());
+ for (String shouldAbsentItem : shouldAbsent) {
+ assertTrue(String.format("Shouldn't contain proposal '%s'.", shouldAbsentItem),
+ !items.contains(shouldAbsentItem));
+ }
+ }
+
+ private static List resolveLookups(List items) {
+ ArrayList result = new ArrayList(items.size());
+ for (LookupElement item : items) {
+ result.add(item.getLookupString());
+ }
+
+ return result;
+ }
+
+ @NotNull
+ private static List itemsShouldExist(String fileText) {
+ return findListWithPrefix("// EXIST:", fileText);
+ }
+
+ @NotNull
+ private static List itemsShouldAbsent(String fileText) {
+ return findListWithPrefix("// ABSENT:", fileText);
+ }
+
+ @NotNull
+ private static List findListWithPrefix(String prefix, String fileText) {
+ ArrayList result = new ArrayList();
+
+ for (String line : findLinesWithPrefixRemoved(prefix, fileText)) {
+ String[] completions = line.split(",");
+
+ for (String completion : completions) {
+ result.add(completion.trim());
+ }
+ }
+
+ return result;
+ }
+
+ @NotNull
+ private static List findLinesWithPrefixRemoved(String prefix, String fileText) {
+ ArrayList result = new ArrayList();
+
+ for (String line : fileNonEmptyLines(fileText)) {
+ if (line.startsWith(prefix)) {
+ result.add(line.substring(prefix.length()).trim());
+ }
+ }
+
+ return result;
+ }
+
+ @NotNull
+ private static List fileNonEmptyLines(String fileText) {
+ ArrayList result = new ArrayList();
+
+ BufferedReader reader = new BufferedReader(new StringReader(fileText));
+
+ try {
+ String line;
+
+ while ((line = reader.readLine()) != null) {
+ if (!line.isEmpty()) {
+ result.add(line.trim());
+ }
+ }
+ } catch(IOException e) {
+ assert false;
+ }
+
+ return result;
+ }
+}
diff --git a/idea/tests/org/jetbrains/jet/completion/KeywordsCompletionTest.java b/idea/tests/org/jetbrains/jet/completion/KeywordsCompletionTest.java
new file mode 100644
index 00000000000..7cb30ecfe96
--- /dev/null
+++ b/idea/tests/org/jetbrains/jet/completion/KeywordsCompletionTest.java
@@ -0,0 +1,61 @@
+package org.jetbrains.jet.completion;
+
+import junit.framework.TestSuite;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.JetTestCaseBuilder;
+import org.jetbrains.jet.plugin.PluginTestCaseBase;
+
+import java.io.File;
+
+/**
+ * Test auto completion messages
+ *
+ * @author Nikolay.Krasko
+ */
+public class KeywordsCompletionTest extends JetCompletionTestBase {
+
+ private final String myPath;
+ private final String myName;
+
+ public KeywordsCompletionTest(@NotNull String path, @NotNull String name) {
+ myPath = path;
+ myName = name;
+
+ // Set name explicitly because otherwise there will be "TestCase.fName cannot be null"
+ setName("testComletionExecute");
+ }
+
+ public void testComletionExecute() {
+ doTest();
+ }
+
+ @Override
+ protected String getTestDataPath() {
+ return new File(PluginTestCaseBase.getTestDataPathBase(), myPath).getPath() +
+ File.separator;
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return "test" + myName;
+ }
+
+ @NotNull
+ public static TestSuite suite() {
+ TestSuite suite = new TestSuite();
+
+ JetTestCaseBuilder.appendTestsInDirectory(
+ PluginTestCaseBase.getTestDataPathBase(), "/completion/keywords/", false,
+ JetTestCaseBuilder.emptyFilter, new JetTestCaseBuilder.NamedTestFactory() {
+
+ @NotNull
+ @Override
+ public junit.framework.Test createTest(@NotNull String dataPath, @NotNull String name) {
+ return new KeywordsCompletionTest(dataPath, name);
+ }
+ }, suite);
+
+ return suite;
+ }
+}
\ No newline at end of file