KT-8576 Parameter name&type completion: don't auto-popup for the second time
#KT-8576
This commit is contained in:
+20
-11
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.psi.*
|
|||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||||
|
|
||||||
@@ -144,10 +145,17 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
|
|||||||
}
|
}
|
||||||
|
|
||||||
public fun shouldDisableAutoPopup(): Boolean {
|
public fun shouldDisableAutoPopup(): Boolean {
|
||||||
return when (completionKind) {
|
if (completionKind == CompletionKind.PARAMETER_NAME || completionKind == CompletionKind.ANNOTATION_TYPES_OR_PARAMETER_NAME) {
|
||||||
CompletionKind.PARAMETER_NAME, CompletionKind.ANNOTATION_TYPES_OR_PARAMETER_NAME -> !shouldCompleteParameterNameAndType()
|
if (LookupCancelWatcher.getInstance(project).wasAutoPopupRecentlyCancelled(parameters.editor, position.startOffset)) {
|
||||||
else -> false
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shouldCompleteParameterNameAndType()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun doComplete() {
|
override fun doComplete() {
|
||||||
@@ -159,23 +167,24 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
|
|||||||
override fun accepts(prefix: String, context: ProcessingContext?) = prefix.isNotEmpty() && prefix.last().isUpperCase()
|
override fun accepts(prefix: String, context: ProcessingContext?) = prefix.isNotEmpty() && prefix.last().isUpperCase()
|
||||||
})
|
})
|
||||||
collector.restartCompletionOnPrefixChange(prefixPattern)
|
collector.restartCompletionOnPrefixChange(prefixPattern)
|
||||||
}
|
|
||||||
|
|
||||||
if (completionKind == CompletionKind.PARAMETER_NAME || completionKind == CompletionKind.ANNOTATION_TYPES_OR_PARAMETER_NAME) {
|
|
||||||
collector.addLookupElementPostProcessor { lookupElement ->
|
collector.addLookupElementPostProcessor { lookupElement ->
|
||||||
lookupElement.putUserData(KotlinCompletionCharFilter.SUPPRESS_ITEM_SELECTION_BY_CHARS_ON_TYPING, Unit)
|
lookupElement.putUserData(KotlinCompletionCharFilter.SUPPRESS_ITEM_SELECTION_BY_CHARS_ON_TYPING, Unit)
|
||||||
lookupElement.putUserData(KotlinCompletionCharFilter.HIDE_LOOKUP_ON_COLON, Unit)
|
lookupElement.putUserData(KotlinCompletionCharFilter.HIDE_LOOKUP_ON_COLON, Unit)
|
||||||
|
if (parameters.isAutoPopup) {
|
||||||
|
lookupElement.putUserData(LookupCancelWatcher.DO_NOT_REPEAT_AUTO_POPUP_AT, position.startOffset)
|
||||||
|
}
|
||||||
lookupElement
|
lookupElement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parameterNameAndTypeCompletion.addFromParametersInFile(position, resolutionFacade, isVisibleFilter)
|
||||||
|
flushToResultSet()
|
||||||
|
|
||||||
|
parameterNameAndTypeCompletion.addFromImportedClasses(position, bindingContext, isVisibleFilter)
|
||||||
|
flushToResultSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (completionKind != CompletionKind.NAMED_ARGUMENTS_ONLY) {
|
if (completionKind != CompletionKind.NAMED_ARGUMENTS_ONLY) {
|
||||||
parameterNameAndTypeCompletion?.addFromParametersInFile(position, resolutionFacade, isVisibleFilter)
|
|
||||||
flushToResultSet()
|
|
||||||
|
|
||||||
parameterNameAndTypeCompletion?.addFromImportedClasses(position, bindingContext, isVisibleFilter)
|
|
||||||
flushToResultSet()
|
|
||||||
|
|
||||||
collector.addDescriptorElements(referenceVariants, suppressAutoInsertion = false)
|
collector.addDescriptorElements(referenceVariants, suppressAutoInsertion = false)
|
||||||
|
|
||||||
val keywordsPrefix = prefix.substringBefore('@') // if there is '@' in the prefix - use shorter prefix to not loose 'this' etc
|
val keywordsPrefix = prefix.substringBefore('@') // if there is '@' in the prefix - use shorter prefix to not loose 'this' etc
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 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.completion
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.lookup.Lookup
|
||||||
|
import com.intellij.codeInsight.lookup.LookupAdapter
|
||||||
|
import com.intellij.codeInsight.lookup.LookupEvent
|
||||||
|
import com.intellij.codeInsight.lookup.LookupManager
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
import com.intellij.openapi.components.AbstractProjectComponent
|
||||||
|
import com.intellij.openapi.components.ServiceManager
|
||||||
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.editor.EditorFactory
|
||||||
|
import com.intellij.openapi.editor.RangeMarker
|
||||||
|
import com.intellij.openapi.editor.event.*
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.util.Key
|
||||||
|
|
||||||
|
class LookupCancelWatcher(project: Project) : AbstractProjectComponent(project) {
|
||||||
|
private class Reminiscence(editor: Editor, offset: Int) {
|
||||||
|
var editor: Editor? = editor
|
||||||
|
private var marker: RangeMarker? = editor.document.createRangeMarker(offset, offset)
|
||||||
|
|
||||||
|
// forget about auto-popup cancellation when the caret is moved to the start or before it
|
||||||
|
private var editorListener: CaretListener? = object : CaretAdapter() {
|
||||||
|
override fun caretPositionChanged(e: CaretEvent) {
|
||||||
|
if (!marker!!.isValid || editor.logicalPositionToOffset(e.newPosition) <= offset) {
|
||||||
|
dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
ApplicationManager.getApplication()!!.assertIsDispatchThread()
|
||||||
|
editor.caretModel.addCaretListener(editorListener!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun matches(editor: Editor, offset: Int): Boolean {
|
||||||
|
return editor == this.editor && marker?.startOffset == offset
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dispose() {
|
||||||
|
ApplicationManager.getApplication()!!.assertIsDispatchThread()
|
||||||
|
if (marker != null) {
|
||||||
|
editor!!.caretModel.removeCaretListener(editorListener!!)
|
||||||
|
marker = null
|
||||||
|
editor = null
|
||||||
|
editorListener = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var lastReminiscence: Reminiscence? = null
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun getInstance(project: Project): LookupCancelWatcher = ServiceManager.getService(project, javaClass())
|
||||||
|
|
||||||
|
val DO_NOT_REPEAT_AUTO_POPUP_AT = Key<Int>("LookupCancelWatcher.DO_NOT_REPEAT_AUTO_POPUP_AT")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun wasAutoPopupRecentlyCancelled(editor: Editor, offset: Int): Boolean {
|
||||||
|
return lastReminiscence?.matches(editor, offset) ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
private val lookupCancelListener = object : LookupAdapter() {
|
||||||
|
override fun lookupCanceled(event: LookupEvent) {
|
||||||
|
val lookup = event.lookup
|
||||||
|
if (event.isCanceledExplicitly && lookup.isCompletion) {
|
||||||
|
val offset = lookup.currentItem?.getUserData(DO_NOT_REPEAT_AUTO_POPUP_AT)
|
||||||
|
if (offset != null) {
|
||||||
|
lastReminiscence?.dispose()
|
||||||
|
lastReminiscence = Reminiscence(lookup.editor, offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initComponent() {
|
||||||
|
EditorFactory.getInstance().addEditorFactoryListener(
|
||||||
|
object : EditorFactoryAdapter() {
|
||||||
|
override fun editorReleased(event: EditorFactoryEvent) {
|
||||||
|
if (lastReminiscence?.editor == event.editor) {
|
||||||
|
lastReminiscence!!.dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
myProject)
|
||||||
|
|
||||||
|
LookupManager.getInstance(myProject).addPropertyChangeListener { event ->
|
||||||
|
if (event.propertyName == LookupManager.PROP_ACTIVE_LOOKUP) {
|
||||||
|
(event.newValue as Lookup?)?.addLookupListener(lookupCancelListener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,6 +36,9 @@
|
|||||||
<component>
|
<component>
|
||||||
<implementation-class>org.jetbrains.kotlin.idea.js.KotlinJavaScriptLibraryManager</implementation-class>
|
<implementation-class>org.jetbrains.kotlin.idea.js.KotlinJavaScriptLibraryManager</implementation-class>
|
||||||
</component>
|
</component>
|
||||||
|
<component>
|
||||||
|
<implementation-class>org.jetbrains.kotlin.idea.completion.LookupCancelWatcher</implementation-class>
|
||||||
|
</component>
|
||||||
</project-components>
|
</project-components>
|
||||||
|
|
||||||
<application-components>
|
<application-components>
|
||||||
@@ -310,7 +313,7 @@
|
|||||||
<typeDeclarationProvider implementation="org.jetbrains.kotlin.idea.codeInsight.JetTypeDeclarationProvider"/>
|
<typeDeclarationProvider implementation="org.jetbrains.kotlin.idea.codeInsight.JetTypeDeclarationProvider"/>
|
||||||
|
|
||||||
<completion.contributor language="jet"
|
<completion.contributor language="jet"
|
||||||
id="JetCompletionContributor"
|
id="KotlinCompletionContributor"
|
||||||
order="first"
|
order="first"
|
||||||
implementationClass="org.jetbrains.kotlin.idea.completion.KotlinCompletionContributor"/>
|
implementationClass="org.jetbrains.kotlin.idea.completion.KotlinCompletionContributor"/>
|
||||||
<completion.contributor language="jet"
|
<completion.contributor language="jet"
|
||||||
|
|||||||
Reference in New Issue
Block a user