Move: Implement Kotlin-specific editor for class name
#KT-13192 Fixed
This commit is contained in:
@@ -142,7 +142,7 @@ abstract class CompletionSession(
|
|||||||
|
|
||||||
// LookupElementsCollector instantiation is deferred because virtual call to createSorter uses data from derived classes
|
// LookupElementsCollector instantiation is deferred because virtual call to createSorter uses data from derived classes
|
||||||
protected val collector: LookupElementsCollector by lazy(LazyThreadSafetyMode.NONE) {
|
protected val collector: LookupElementsCollector by lazy(LazyThreadSafetyMode.NONE) {
|
||||||
LookupElementsCollector(prefixMatcher, parameters, resultSet, createSorter())
|
LookupElementsCollector(prefixMatcher, parameters, resultSet, createSorter(), (file as? KtCodeFragment)?.extraCompletionFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected val searchScope: GlobalSearchScope = getResolveScope(parameters.originalFile as KtFile)
|
protected val searchScope: GlobalSearchScope = getResolveScope(parameters.originalFile as KtFile)
|
||||||
|
|||||||
@@ -418,4 +418,6 @@ fun OffsetMap.tryGetOffset(key: OffsetKey): Int? {
|
|||||||
catch(e: Exception) {
|
catch(e: Exception) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var KtCodeFragment.extraCompletionFilter: ((LookupElement) -> Boolean)? by CopyableUserDataProperty(Key.create("EXTRA_COMPLETION_FILTER"))
|
||||||
@@ -159,6 +159,7 @@ object KeywordCompletion {
|
|||||||
CommentFilter(),
|
CommentFilter(),
|
||||||
ParentFilter(ClassFilter(KtLiteralStringTemplateEntry::class.java)),
|
ParentFilter(ClassFilter(KtLiteralStringTemplateEntry::class.java)),
|
||||||
ParentFilter(ClassFilter(KtConstantExpression::class.java)),
|
ParentFilter(ClassFilter(KtConstantExpression::class.java)),
|
||||||
|
FileFilter(ClassFilter(KtTypeCodeFragment::class.java)),
|
||||||
LeftNeighbour(TextFilter(".")),
|
LeftNeighbour(TextFilter(".")),
|
||||||
LeftNeighbour(TextFilter("?."))
|
LeftNeighbour(TextFilter("?."))
|
||||||
))
|
))
|
||||||
@@ -182,6 +183,17 @@ object KeywordCompletion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class FileFilter(filter : ElementFilter) : PositionElementFilter() {
|
||||||
|
init {
|
||||||
|
setFilter(filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isAcceptable(element : Any?, context : PsiElement?) : Boolean {
|
||||||
|
val file = (element as? PsiElement)?.containingFile
|
||||||
|
return file != null && (filter?.isAcceptable(file, context) ?: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun buildFilter(position: PsiElement): (KtKeywordToken) -> Boolean {
|
private fun buildFilter(position: PsiElement): (KtKeywordToken) -> Boolean {
|
||||||
var parent = position.parent
|
var parent = position.parent
|
||||||
var prevParent = position
|
var prevParent = position
|
||||||
|
|||||||
+5
-2
@@ -32,7 +32,8 @@ class LookupElementsCollector(
|
|||||||
private val prefixMatcher: PrefixMatcher,
|
private val prefixMatcher: PrefixMatcher,
|
||||||
private val completionParameters: CompletionParameters,
|
private val completionParameters: CompletionParameters,
|
||||||
resultSet: CompletionResultSet,
|
resultSet: CompletionResultSet,
|
||||||
sorter: CompletionSorter
|
sorter: CompletionSorter,
|
||||||
|
private val filter: ((LookupElement) -> Boolean)?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var bestMatchingDegree = Int.MIN_VALUE
|
var bestMatchingDegree = Int.MIN_VALUE
|
||||||
@@ -132,7 +133,9 @@ class LookupElementsCollector(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
elements.add(result)
|
if (filter?.invoke(result) ?: true) {
|
||||||
|
elements.add(result)
|
||||||
|
}
|
||||||
|
|
||||||
val matchingDegree = RealPrefixMatchingWeigher.getBestMatchingDegree(result, prefixMatcher)
|
val matchingDegree = RealPrefixMatchingWeigher.getBestMatchingDegree(result, prefixMatcher)
|
||||||
bestMatchingDegree = Math.max(bestMatchingDegree, matchingDegree)
|
bestMatchingDegree = Math.max(bestMatchingDegree, matchingDegree)
|
||||||
|
|||||||
+25
-7
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui;
|
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui;
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElement;
|
||||||
import com.intellij.ide.util.ClassFilter;
|
import com.intellij.ide.util.ClassFilter;
|
||||||
import com.intellij.ide.util.TreeClassChooser;
|
import com.intellij.ide.util.TreeClassChooser;
|
||||||
import com.intellij.ide.util.TreeJavaClassChooserDialog;
|
import com.intellij.ide.util.TreeJavaClassChooserDialog;
|
||||||
@@ -23,9 +24,9 @@ import com.intellij.openapi.editor.event.DocumentAdapter;
|
|||||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||||
import com.intellij.openapi.options.ConfigurationException;
|
import com.intellij.openapi.options.ConfigurationException;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.psi.JavaCodeFragment;
|
|
||||||
import com.intellij.psi.JavaPsiFacade;
|
import com.intellij.psi.JavaPsiFacade;
|
||||||
import com.intellij.psi.PsiClass;
|
import com.intellij.psi.PsiClass;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.search.GlobalSearchScope;
|
import com.intellij.psi.search.GlobalSearchScope;
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
import com.intellij.refactoring.RefactoringBundle;
|
import com.intellij.refactoring.RefactoringBundle;
|
||||||
@@ -34,18 +35,21 @@ import com.intellij.refactoring.classMembers.MemberInfoChange;
|
|||||||
import com.intellij.refactoring.move.MoveCallback;
|
import com.intellij.refactoring.move.MoveCallback;
|
||||||
import com.intellij.refactoring.move.MoveHandler;
|
import com.intellij.refactoring.move.MoveHandler;
|
||||||
import com.intellij.refactoring.ui.RefactoringDialog;
|
import com.intellij.refactoring.ui.RefactoringDialog;
|
||||||
import com.intellij.ui.ReferenceEditorComboWithBrowseButton;
|
|
||||||
import kotlin.collections.CollectionsKt;
|
import kotlin.collections.CollectionsKt;
|
||||||
import kotlin.jvm.functions.Function1;
|
import kotlin.jvm.functions.Function1;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.asJava.LightClassUtilsKt;
|
import org.jetbrains.kotlin.asJava.LightClassUtilsKt;
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration;
|
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration;
|
||||||
|
import org.jetbrains.kotlin.idea.completion.CompletionUtilsKt;
|
||||||
|
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject;
|
||||||
import org.jetbrains.kotlin.idea.projectView.KtClassOrObjectTreeNode;
|
import org.jetbrains.kotlin.idea.projectView.KtClassOrObjectTreeNode;
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringUtilKt;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo;
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel;
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionTable;
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionTable;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*;
|
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*;
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.ui.KotlinTypeReferenceEditorComboWithBrowseButton;
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
@@ -62,7 +66,7 @@ public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
|
|||||||
private JPanel mainPanel;
|
private JPanel mainPanel;
|
||||||
private JTextField originalClassField;
|
private JTextField originalClassField;
|
||||||
private JPanel membersInfoPanel;
|
private JPanel membersInfoPanel;
|
||||||
private ReferenceEditorComboWithBrowseButton targetClassChooser;
|
private KotlinTypeReferenceEditorComboWithBrowseButton targetClassChooser;
|
||||||
private JCheckBox openInEditorCheckBox;
|
private JCheckBox openInEditorCheckBox;
|
||||||
private JPanel targetClassChooserPanel;
|
private JPanel targetClassChooserPanel;
|
||||||
private KotlinMemberSelectionTable memberTable;
|
private KotlinMemberSelectionTable memberTable;
|
||||||
@@ -96,7 +100,7 @@ public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
|
|||||||
originalClassField.setText(originalClass.getFqName().asString());
|
originalClassField.setText(originalClass.getFqName().asString());
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
targetClassChooser = new ReferenceEditorComboWithBrowseButton(
|
targetClassChooser = new KotlinTypeReferenceEditorComboWithBrowseButton(
|
||||||
new ActionListener() {
|
new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
@@ -148,10 +152,24 @@ public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
initialTargetClass.getFqName().asString(),
|
initialTargetClass.getFqName().asString(),
|
||||||
myProject,
|
originalClass,
|
||||||
true,
|
|
||||||
JavaCodeFragment.VisibilityChecker.PROJECT_SCOPE_VISIBLE,
|
|
||||||
RECENTS_KEY);
|
RECENTS_KEY);
|
||||||
|
KtTypeCodeFragment codeFragment = targetClassChooser.getCodeFragment();
|
||||||
|
if (codeFragment != null) {
|
||||||
|
CompletionUtilsKt.setExtraCompletionFilter(
|
||||||
|
codeFragment,
|
||||||
|
new Function1<LookupElement, Boolean>() {
|
||||||
|
@Override
|
||||||
|
public Boolean invoke(LookupElement lookupElement) {
|
||||||
|
Object lookupObject = lookupElement.getObject();
|
||||||
|
if (!(lookupObject instanceof DeclarationLookupObject)) return false;
|
||||||
|
PsiElement psiElement = ((DeclarationLookupObject) lookupObject).getPsiElement();
|
||||||
|
if (!(psiElement instanceof KtClassOrObject)) return false;
|
||||||
|
return KotlinRefactoringUtilKt.canRefactor(psiElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
targetClassChooser.getChildComponent().getDocument().addDocumentListener(
|
targetClassChooser.getChildComponent().getDocument().addDocumentListener(
|
||||||
new DocumentAdapter() {
|
new DocumentAdapter() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2000-2009 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.
|
||||||
|
*/
|
||||||
|
package org.jetbrains.kotlin.idea.refactoring.ui
|
||||||
|
|
||||||
|
import com.intellij.openapi.editor.Document
|
||||||
|
import com.intellij.openapi.ui.ComponentWithBrowseButton
|
||||||
|
import com.intellij.psi.PsiDocumentManager
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.ui.EditorComboBox
|
||||||
|
import com.intellij.ui.RecentsManager
|
||||||
|
import com.intellij.ui.TextAccessor
|
||||||
|
import com.intellij.util.ArrayUtil
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||||
|
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||||
|
import org.jetbrains.kotlin.psi.KtTypeCodeFragment
|
||||||
|
import java.awt.event.ActionListener
|
||||||
|
|
||||||
|
class KotlinTypeReferenceEditorComboWithBrowseButton(
|
||||||
|
browseActionListener: ActionListener,
|
||||||
|
text: String?,
|
||||||
|
contextElement: PsiElement,
|
||||||
|
recentsKey: String
|
||||||
|
) : ComponentWithBrowseButton<EditorComboBox>(
|
||||||
|
EditorComboBox(createDocument(text, contextElement), contextElement.project, KotlinFileType.INSTANCE),
|
||||||
|
browseActionListener
|
||||||
|
), TextAccessor {
|
||||||
|
companion object {
|
||||||
|
private fun createDocument(text: String?, contextElement: PsiElement): Document? {
|
||||||
|
val codeFragment = KtPsiFactory(contextElement).createTypeCodeFragment(text ?: "", contextElement)
|
||||||
|
return PsiDocumentManager.getInstance(contextElement.project).getDocument(codeFragment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val project = contextElement.project
|
||||||
|
|
||||||
|
init {
|
||||||
|
RecentsManager.getInstance(contextElement.project).getRecentEntries(recentsKey)?.let {
|
||||||
|
childComponent.setHistory(ArrayUtil.toStringArray(it))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text != null) {
|
||||||
|
if (text.isNotEmpty()) {
|
||||||
|
childComponent.prependItem(text)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
childComponent.selectedItem = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getText() = childComponent.text.trim { it <= ' ' }
|
||||||
|
|
||||||
|
override fun setText(text: String) {
|
||||||
|
childComponent.text = text
|
||||||
|
}
|
||||||
|
|
||||||
|
val codeFragment: KtTypeCodeFragment?
|
||||||
|
get() = PsiDocumentManager.getInstance(project).getPsiFile(childComponent.document) as? KtTypeCodeFragment
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user