Keyword correction: more correct behavior + smaller file text
This commit is contained in:
@@ -31,6 +31,7 @@ import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.getParentByType
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.prevLeaf
|
||||
import org.jetbrains.jet.plugin.completion.handlers.KotlinKeywordInsertHandler
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.siblings
|
||||
|
||||
class KeywordLookupObject(val keyword: String)
|
||||
|
||||
@@ -47,7 +48,7 @@ object KeywordCompletion {
|
||||
|
||||
if (!GENERAL_FILTER.isAcceptable(position, position)) return
|
||||
|
||||
val parserFilter = buildParserFilter(position)
|
||||
val parserFilter = buildFilter(position)
|
||||
for (keyword in ALL_KEYWORDS) {
|
||||
if (prefixMatcher.prefixMatches(keyword) && parserFilter(keyword)) {
|
||||
val element = LookupElementBuilder.create(KeywordLookupObject(keyword), keyword)
|
||||
@@ -90,27 +91,27 @@ object KeywordCompletion {
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildParserFilter(position: PsiElement): (String) -> Boolean {
|
||||
private fun buildFilter(position: PsiElement): (String) -> Boolean {
|
||||
var parent = position.getParent()
|
||||
var prevParent = position
|
||||
while (parent != null) {
|
||||
val _parent = parent
|
||||
when (_parent) {
|
||||
is JetBlockExpression -> {
|
||||
return buildParserFilterWithContextElement("fun foo() { ", prevParent, position)
|
||||
return buildFilterWithContext("fun foo() { ", prevParent, position)
|
||||
}
|
||||
|
||||
is JetWithExpressionInitializer -> {
|
||||
val initializer = _parent.getInitializer()
|
||||
if (prevParent == initializer) {
|
||||
return buildParserFilterWithContextElement("val v = ", initializer, position)
|
||||
return buildFilterWithContext("val v = ", initializer, position)
|
||||
}
|
||||
}
|
||||
|
||||
is JetParameter -> {
|
||||
val default = _parent.getDefaultValue()
|
||||
if (prevParent == default) {
|
||||
return buildParserFilterWithContextElement("val v = ", default, position)
|
||||
return buildFilterWithContext("val v = ", default, position)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,29 +119,36 @@ object KeywordCompletion {
|
||||
if (_parent is JetDeclaration) {
|
||||
val scope = _parent.getParent()
|
||||
when (scope) {
|
||||
is JetClassOrObject -> return buildParserFilterWithContextElement("class X { ", _parent, position)
|
||||
is JetFile -> return buildParserFilterWithContextElement("", _parent, position)
|
||||
is JetClassOrObject -> return buildFilterWithReducedContext("class X { ", _parent, position)
|
||||
is JetFile -> return buildFilterWithReducedContext("", _parent, position)
|
||||
}
|
||||
}
|
||||
|
||||
prevParent = parent!!
|
||||
parent = parent!!.getParent()
|
||||
prevParent = _parent
|
||||
parent = _parent.getParent()
|
||||
}
|
||||
|
||||
val builder = StringBuilder()
|
||||
buildReducedContextBefore(builder, position)
|
||||
return buildParserFilterByText(builder.toString(), position.getProject())
|
||||
return buildFilterWithReducedContext("", null, position)
|
||||
}
|
||||
|
||||
private fun buildParserFilterWithContextElement(prefixText: String,
|
||||
contextElement: PsiElement,
|
||||
position: PsiElement): (String) -> Boolean {
|
||||
private fun buildFilterWithContext(prefixText: String,
|
||||
contextElement: PsiElement,
|
||||
position: PsiElement): (String) -> Boolean {
|
||||
val offset = position.getStartOffsetInAncestor(contextElement)
|
||||
val truncatedContext = contextElement.getText()!!.substring(0, offset)
|
||||
return buildParserFilterByText(prefixText + truncatedContext, contextElement.getProject())
|
||||
return buildFilterByText(prefixText + truncatedContext, contextElement.getProject())
|
||||
}
|
||||
|
||||
private fun buildParserFilterByText(prefixText: String, project: Project): (String) -> Boolean {
|
||||
private fun buildFilterWithReducedContext(prefixText: String,
|
||||
contextElement: PsiElement?,
|
||||
position: PsiElement): (String) -> Boolean {
|
||||
val builder = StringBuilder()
|
||||
buildReducedContextBefore(builder, position, contextElement)
|
||||
return buildFilterByText(prefixText + builder.toString(), position.getProject())
|
||||
}
|
||||
|
||||
|
||||
private fun buildFilterByText(prefixText: String, project: Project): (String) -> Boolean {
|
||||
val psiFactory = JetPsiFactory(project)
|
||||
return { keyword ->
|
||||
val file = psiFactory.createFile(prefixText + keyword)
|
||||
@@ -158,17 +166,26 @@ object KeywordCompletion {
|
||||
}
|
||||
}
|
||||
|
||||
// builds text before position element excluding declarations
|
||||
private fun buildReducedContextBefore(builder: StringBuilder, position: PsiElement) {
|
||||
// builds text within scope (or from the start of the file) before position element excluding almost all declarations
|
||||
private fun buildReducedContextBefore(builder: StringBuilder, position: PsiElement, scope: PsiElement?) {
|
||||
if (position == scope) return
|
||||
val parent = position.getParent() ?: return
|
||||
|
||||
buildReducedContextBefore(builder, parent)
|
||||
buildReducedContextBefore(builder, parent, scope)
|
||||
|
||||
val prevDeclaration = position.siblings(forward = false, withItself = false).firstOrNull { it is JetDeclaration }
|
||||
|
||||
var child = parent.getFirstChild()
|
||||
while (child != position) {
|
||||
if (child !is JetDeclaration) {
|
||||
if (child is JetDeclaration) {
|
||||
if (child == prevDeclaration) {
|
||||
builder.append(child!!.getText()) //TODO: skip code blocks, class body inside,
|
||||
}
|
||||
}
|
||||
else {
|
||||
builder.append(child!!.getText())
|
||||
}
|
||||
|
||||
child = child!!.getNextSibling()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
fun foo() {
|
||||
bar()
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
foo()
|
||||
}
|
||||
|
||||
var a : Int
|
||||
<caret>
|
||||
|
||||
// EXIST: abstract
|
||||
// EXIST: annotation
|
||||
// EXIST: by
|
||||
// EXIST: class
|
||||
// EXIST: enum
|
||||
// EXIST: final
|
||||
// EXIST: fun
|
||||
// EXIST: get
|
||||
// EXIST: in
|
||||
/*why?*/
|
||||
// EXIST: inner
|
||||
// EXIST: internal
|
||||
// EXIST: object
|
||||
// EXIST: open
|
||||
// EXIST: out
|
||||
/*why?*/
|
||||
// EXIST: override
|
||||
// EXIST: private
|
||||
// EXIST: protected
|
||||
// EXIST: public
|
||||
// EXIST: set
|
||||
// EXIST: trait
|
||||
// EXIST: val
|
||||
// EXIST: var
|
||||
// EXIST: vararg
|
||||
/*why?*/
|
||||
// NUMBER: 23
|
||||
@@ -0,0 +1,12 @@
|
||||
class C(<caret>)
|
||||
|
||||
// EXIST: in
|
||||
/*TODO*/
|
||||
// EXIST: val
|
||||
// EXIST: var
|
||||
// EXIST: public
|
||||
// EXIST: private
|
||||
// EXIST: protected
|
||||
// EXIST: internal
|
||||
// EXIST: override
|
||||
// NUMBER: 8
|
||||
@@ -17,13 +17,9 @@
|
||||
package org.jetbrains.jet.completion;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.jetbrains.jet.JetTestUtils;
|
||||
import org.jetbrains.jet.test.InnerTestClasses;
|
||||
import org.jetbrains.jet.test.TestMetadata;
|
||||
import org.jetbrains.jet.JUnit3RunnerWithInners;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -74,6 +70,12 @@ public class KeywordCompletionTestGenerated extends AbstractKeywordCompletionTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("GlobalPropertyAccessors.kt")
|
||||
public void testGlobalPropertyAccessors() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/keywords/GlobalPropertyAccessors.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InArgumentList.kt")
|
||||
public void testInArgumentList() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/keywords/InArgumentList.kt");
|
||||
|
||||
Reference in New Issue
Block a user