diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/CastReceiverInsertHandler.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/CastReceiverInsertHandler.kt new file mode 100644 index 00000000000..8ebfeb0798a --- /dev/null +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/CastReceiverInsertHandler.kt @@ -0,0 +1,57 @@ +/* + * 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.handlers + +import com.intellij.codeInsight.completion.InsertionContext +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.idea.core.completion.DeclarationDescriptorLookupObject +import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers +import org.jetbrains.kotlin.idea.util.ShortenReferences +import org.jetbrains.kotlin.psi.* + +object CastReceiverInsertHandler : KotlinCallableInsertHandler() { + override fun handleInsert(context: InsertionContext, item: LookupElement) { + super.handleInsert(context, item) + + val expression = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), javaClass(), false) + val qualifiedExpression = PsiTreeUtil.getParentOfType(expression, javaClass(), true) + if (qualifiedExpression != null) { + val receiver = qualifiedExpression.getReceiverExpression() + + val descriptor = (item.getObject() as? DeclarationDescriptorLookupObject)?.descriptor as CallableDescriptor + val project = context.getProject() + + val thisObj = if (descriptor.getExtensionReceiverParameter() != null) descriptor.getExtensionReceiverParameter() else descriptor.getDispatchReceiverParameter() + val fqName = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(thisObj.getType().getConstructor().getDeclarationDescriptor()) + + val parentCast = JetPsiFactory(project).createExpression("(expr as $fqName)") as JetParenthesizedExpression + val cast = parentCast.getExpression() as JetBinaryExpressionWithTypeRHS + cast.getLeft().replace(receiver) + + val psiDocumentManager = PsiDocumentManager.getInstance(project) + psiDocumentManager.commitAllDocuments() + psiDocumentManager.doPostponedOperationsAndUnblockDocument(context.getDocument()) + + val expr = receiver.replace(parentCast) as JetParenthesizedExpression + + ShortenReferences.DEFAULT.process((expr.getExpression() as JetBinaryExpressionWithTypeRHS).getRight()) + } + } +} \ No newline at end of file diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinCallableInsertHandler.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinCallableInsertHandler.kt index 627f1e3b4d8..28095eca0be 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinCallableInsertHandler.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinCallableInsertHandler.kt @@ -16,32 +16,18 @@ package org.jetbrains.kotlin.idea.completion.handlers -import com.intellij.codeInsight.AutoPopupController import com.intellij.codeInsight.completion.InsertionContext -import com.intellij.codeInsight.lookup.Lookup import com.intellij.codeInsight.lookup.LookupElement -import com.intellij.openapi.project.Project -import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiDocumentManager -import com.intellij.psi.PsiElement -import com.intellij.psi.codeStyle.CodeStyleSettingsManager -import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.idea.completion.isAfterDot import org.jetbrains.kotlin.idea.core.completion.DeclarationDescriptorLookupObject -import org.jetbrains.kotlin.idea.core.formatter.JetCodeStyleSettings -import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.ImportInsertHelper -import org.jetbrains.kotlin.idea.util.ShortenReferences import org.jetbrains.kotlin.idea.util.application.runWriteAction -import org.jetbrains.kotlin.lexer.JetTokens -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.endOffset -import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType +import org.jetbrains.kotlin.psi.JetFile import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.types.JetType -public abstract class KotlinCallableInsertHandler : BaseDeclarationInsertHandler() { +abstract class KotlinCallableInsertHandler : BaseDeclarationInsertHandler() { public override fun handleInsert(context: InsertionContext, item: LookupElement) { super.handleInsert(context, item) @@ -71,193 +57,3 @@ public abstract class KotlinCallableInsertHandler : BaseDeclarationInsertHandler } } -public object KotlinPropertyInsertHandler : KotlinCallableInsertHandler() { - public override fun handleInsert(context: InsertionContext, item: LookupElement) { - super.handleInsert(context, item) - - if (context.getCompletionChar() == Lookup.REPLACE_SELECT_CHAR) { - deleteEmptyParenthesis(context) - } - } - - private fun deleteEmptyParenthesis(context: InsertionContext) { - val psiDocumentManager = PsiDocumentManager.getInstance(context.getProject()) - psiDocumentManager.commitAllDocuments() - psiDocumentManager.doPostponedOperationsAndUnblockDocument(context.getDocument()) - - val offset = context.getTailOffset() - val document = context.getDocument() - val chars = document.getCharsSequence() - - val lParenOffset = chars.indexOfSkippingSpace('(', offset) ?: return - val rParenOffset = chars.indexOfSkippingSpace(')', lParenOffset + 1) ?: return - - document.deleteString(offset, rParenOffset + 1) - } -} - -public enum class CaretPosition { - IN_BRACKETS - AFTER_BRACKETS -} - -public data class GenerateLambdaInfo(val lambdaType: JetType, val explicitParameters: Boolean) - -public class KotlinFunctionInsertHandler(val caretPosition : CaretPosition, val lambdaInfo: GenerateLambdaInfo?) : KotlinCallableInsertHandler() { - init { - if (caretPosition == CaretPosition.AFTER_BRACKETS && lambdaInfo != null) { - throw IllegalArgumentException("CaretPosition.AFTER_BRACKETS with lambdaInfo != null combination is not supported") - } - } - - public override fun handleInsert(context: InsertionContext, item: LookupElement) { - super.handleInsert(context, item) - - val psiDocumentManager = PsiDocumentManager.getInstance(context.getProject()) - psiDocumentManager.commitAllDocuments() - psiDocumentManager.doPostponedOperationsAndUnblockDocument(context.getDocument()) - - val startOffset = context.getStartOffset() - val element = context.getFile().findElementAt(startOffset) ?: return - - when { - element.getStrictParentOfType() != null -> return - - isInfixCall(element) -> { - if (context.getCompletionChar() == ' ') { - context.setAddCompletionChar(false) - } - - val tailOffset = context.getTailOffset() - context.getDocument().insertString(tailOffset, " ") - context.getEditor().getCaretModel().moveToOffset(tailOffset + 1) - } - - else -> addBrackets(context, element) - } - } - - private fun isInfixCall(context: PsiElement): Boolean { - val parent = context.getParent() - val grandParent = parent?.getParent() - return parent is JetSimpleNameExpression && grandParent is JetBinaryExpression && parent == grandParent.getOperationReference() - } - - private fun addBrackets(context : InsertionContext, offsetElement : PsiElement) { - val completionChar = context.getCompletionChar() - if (completionChar == '(') { //TODO: more correct behavior related to braces type - context.setAddCompletionChar(false) - } - - var offset = context.getTailOffset() - val document = context.getDocument() - val chars = document.getCharsSequence() - - val forceParenthesis = lambdaInfo != null && completionChar == '\t' && chars.charAt(offset) == '(' - val braces = lambdaInfo != null && completionChar != '(' && !forceParenthesis - - val openingBracket = if (braces) '{' else '(' - val closingBracket = if (braces) '}' else ')' - - if (completionChar == Lookup.REPLACE_SELECT_CHAR) { - val offset1 = chars.skipSpaces(offset) - if (offset1 < chars.length()) { - if (chars[offset1] == '<') { - PsiDocumentManager.getInstance(context.getProject()).commitDocument(document) - val token = context.getFile().findElementAt(offset1)!! - if (token.getNode().getElementType() == JetTokens.LT) { - val parent = token.getParent() - if (parent is JetTypeArgumentList && parent.getText().indexOf('\n') < 0/* if type argument list is on multiple lines this is more likely wrong parsing*/) { - offset = parent.endOffset - } - } - } - } - } - - var openingBracketOffset = chars.indexOfSkippingSpace(openingBracket, offset) - var inBracketsShift = 0 - if (openingBracketOffset == null) { - if (braces) { - if (completionChar == ' ' || completionChar == '{') { - context.setAddCompletionChar(false) - } - - if (isInsertSpacesInOneLineFunctionEnabled(context.getProject())) { - document.insertString(offset, " { }") - inBracketsShift = 1 - } - else { - document.insertString(offset, " {}") - } - } - else { - document.insertString(offset, "()") - } - PsiDocumentManager.getInstance(context.getProject()).commitDocument(document) - } - - openingBracketOffset = chars.indexOfSkippingSpace(openingBracket, offset)!! - - val closeBracketOffset = chars.indexOfSkippingSpace(closingBracket, openingBracketOffset + 1) - - val editor = context.getEditor() - if (shouldPlaceCaretInBrackets(completionChar) || closeBracketOffset == null) { - editor.getCaretModel().moveToOffset(openingBracketOffset + 1 + inBracketsShift) - AutoPopupController.getInstance(context.getProject())?.autoPopupParameterInfo(editor, offsetElement) - } - else { - editor.getCaretModel().moveToOffset(closeBracketOffset + 1) - } - - PsiDocumentManager.getInstance(context.getProject()).commitDocument(document) - - if (lambdaInfo != null && lambdaInfo.explicitParameters) { - insertLambdaTemplate(context, TextRange(openingBracketOffset, closeBracketOffset!! + 1), lambdaInfo.lambdaType) - } - } - - private fun shouldPlaceCaretInBrackets(completionChar: Char): Boolean { - if (completionChar == ',' || completionChar == '.' || completionChar == '=') return false - if (completionChar == '(') return true - return caretPosition == CaretPosition.IN_BRACKETS - } - - companion object { - public val NO_PARAMETERS_HANDLER: KotlinFunctionInsertHandler = KotlinFunctionInsertHandler(CaretPosition.AFTER_BRACKETS, null) - public val WITH_PARAMETERS_HANDLER: KotlinFunctionInsertHandler = KotlinFunctionInsertHandler(CaretPosition.IN_BRACKETS, null) - - private fun isInsertSpacesInOneLineFunctionEnabled(project: Project) - = CodeStyleSettingsManager.getSettings(project).getCustomSettings(javaClass())!!.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD - } -} - -object CastReceiverInsertHandler : KotlinCallableInsertHandler() { - override fun handleInsert(context: InsertionContext, item: LookupElement) { - super.handleInsert(context, item) - - val expression = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), javaClass(), false) - val qualifiedExpression = PsiTreeUtil.getParentOfType(expression, javaClass(), true) - if (qualifiedExpression != null) { - val receiver = qualifiedExpression.getReceiverExpression() - - val descriptor = (item.getObject() as? DeclarationDescriptorLookupObject)?.descriptor as CallableDescriptor - val project = context.getProject() - - val thisObj = if (descriptor.getExtensionReceiverParameter() != null) descriptor.getExtensionReceiverParameter() else descriptor.getDispatchReceiverParameter() - val fqName = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(thisObj.getType().getConstructor().getDeclarationDescriptor()) - - val parentCast = JetPsiFactory(project).createExpression("(expr as $fqName)") as JetParenthesizedExpression - val cast = parentCast.getExpression() as JetBinaryExpressionWithTypeRHS - cast.getLeft().replace(receiver) - - val psiDocumentManager = PsiDocumentManager.getInstance(project) - psiDocumentManager.commitAllDocuments() - psiDocumentManager.doPostponedOperationsAndUnblockDocument(context.getDocument()) - - val expr = receiver.replace(parentCast) as JetParenthesizedExpression - - ShortenReferences.DEFAULT.process((expr.getExpression() as JetBinaryExpressionWithTypeRHS).getRight()) - } - } -} diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinClassInsertHandler.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinClassInsertHandler.kt index 729ef21509f..e63ae977563 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinClassInsertHandler.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinClassInsertHandler.kt @@ -31,7 +31,7 @@ import org.jetbrains.kotlin.psi.JetNameReferenceExpression import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode -public object KotlinClassInsertHandler : BaseDeclarationInsertHandler() { +object KotlinClassInsertHandler : BaseDeclarationInsertHandler() { override fun handleInsert(context: InsertionContext, item: LookupElement) { super.handleInsert(context, item) diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinFunctionInsertHandler.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinFunctionInsertHandler.kt new file mode 100644 index 00000000000..a6d6d66c3f6 --- /dev/null +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinFunctionInsertHandler.kt @@ -0,0 +1,172 @@ +/* + * 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.handlers + +import com.intellij.codeInsight.AutoPopupController +import com.intellij.codeInsight.completion.InsertionContext +import com.intellij.codeInsight.lookup.Lookup +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiElement +import com.intellij.psi.codeStyle.CodeStyleSettingsManager +import org.jetbrains.kotlin.idea.core.formatter.JetCodeStyleSettings +import org.jetbrains.kotlin.lexer.JetTokens +import org.jetbrains.kotlin.psi.JetBinaryExpression +import org.jetbrains.kotlin.psi.JetImportDirective +import org.jetbrains.kotlin.psi.JetSimpleNameExpression +import org.jetbrains.kotlin.psi.JetTypeArgumentList +import org.jetbrains.kotlin.psi.psiUtil.endOffset +import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType +import org.jetbrains.kotlin.types.JetType + +enum class CaretPosition { + IN_BRACKETS + AFTER_BRACKETS +} + +data class GenerateLambdaInfo(val lambdaType: JetType, val explicitParameters: Boolean) + +class KotlinFunctionInsertHandler(val caretPosition : CaretPosition, val lambdaInfo: GenerateLambdaInfo?) : KotlinCallableInsertHandler() { + init { + if (caretPosition == CaretPosition.AFTER_BRACKETS && lambdaInfo != null) { + throw IllegalArgumentException("CaretPosition.AFTER_BRACKETS with lambdaInfo != null combination is not supported") + } + } + + public override fun handleInsert(context: InsertionContext, item: LookupElement) { + super.handleInsert(context, item) + + val psiDocumentManager = PsiDocumentManager.getInstance(context.getProject()) + psiDocumentManager.commitAllDocuments() + psiDocumentManager.doPostponedOperationsAndUnblockDocument(context.getDocument()) + + val startOffset = context.getStartOffset() + val element = context.getFile().findElementAt(startOffset) ?: return + + when { + element.getStrictParentOfType() != null -> return + + isInfixCall(element) -> { + if (context.getCompletionChar() == ' ') { + context.setAddCompletionChar(false) + } + + val tailOffset = context.getTailOffset() + context.getDocument().insertString(tailOffset, " ") + context.getEditor().getCaretModel().moveToOffset(tailOffset + 1) + } + + else -> addBrackets(context, element) + } + } + + private fun isInfixCall(context: PsiElement): Boolean { + val parent = context.getParent() + val grandParent = parent?.getParent() + return parent is JetSimpleNameExpression && grandParent is JetBinaryExpression && parent == grandParent.getOperationReference() + } + + private fun addBrackets(context : InsertionContext, offsetElement : PsiElement) { + val completionChar = context.getCompletionChar() + if (completionChar == '(') { //TODO: more correct behavior related to braces type + context.setAddCompletionChar(false) + } + + var offset = context.getTailOffset() + val document = context.getDocument() + val chars = document.getCharsSequence() + + val forceParenthesis = lambdaInfo != null && completionChar == '\t' && chars.charAt(offset) == '(' + val braces = lambdaInfo != null && completionChar != '(' && !forceParenthesis + + val openingBracket = if (braces) '{' else '(' + val closingBracket = if (braces) '}' else ')' + + if (completionChar == Lookup.REPLACE_SELECT_CHAR) { + val offset1 = chars.skipSpaces(offset) + if (offset1 < chars.length()) { + if (chars[offset1] == '<') { + PsiDocumentManager.getInstance(context.getProject()).commitDocument(document) + val token = context.getFile().findElementAt(offset1)!! + if (token.getNode().getElementType() == JetTokens.LT) { + val parent = token.getParent() + if (parent is JetTypeArgumentList && parent.getText().indexOf('\n') < 0/* if type argument list is on multiple lines this is more likely wrong parsing*/) { + offset = parent.endOffset + } + } + } + } + } + + var openingBracketOffset = chars.indexOfSkippingSpace(openingBracket, offset) + var inBracketsShift = 0 + if (openingBracketOffset == null) { + if (braces) { + if (completionChar == ' ' || completionChar == '{') { + context.setAddCompletionChar(false) + } + + if (isInsertSpacesInOneLineFunctionEnabled(context.getProject())) { + document.insertString(offset, " { }") + inBracketsShift = 1 + } + else { + document.insertString(offset, " {}") + } + } + else { + document.insertString(offset, "()") + } + PsiDocumentManager.getInstance(context.getProject()).commitDocument(document) + } + + openingBracketOffset = chars.indexOfSkippingSpace(openingBracket, offset)!! + + val closeBracketOffset = chars.indexOfSkippingSpace(closingBracket, openingBracketOffset + 1) + + val editor = context.getEditor() + if (shouldPlaceCaretInBrackets(completionChar) || closeBracketOffset == null) { + editor.getCaretModel().moveToOffset(openingBracketOffset + 1 + inBracketsShift) + AutoPopupController.getInstance(context.getProject())?.autoPopupParameterInfo(editor, offsetElement) + } + else { + editor.getCaretModel().moveToOffset(closeBracketOffset + 1) + } + + PsiDocumentManager.getInstance(context.getProject()).commitDocument(document) + + if (lambdaInfo != null && lambdaInfo.explicitParameters) { + insertLambdaTemplate(context, TextRange(openingBracketOffset, closeBracketOffset!! + 1), lambdaInfo.lambdaType) + } + } + + private fun shouldPlaceCaretInBrackets(completionChar: Char): Boolean { + if (completionChar == ',' || completionChar == '.' || completionChar == '=') return false + if (completionChar == '(') return true + return caretPosition == CaretPosition.IN_BRACKETS + } + + companion object { + public val NO_PARAMETERS_HANDLER: KotlinFunctionInsertHandler = KotlinFunctionInsertHandler(CaretPosition.AFTER_BRACKETS, null) + public val WITH_PARAMETERS_HANDLER: KotlinFunctionInsertHandler = KotlinFunctionInsertHandler(CaretPosition.IN_BRACKETS, null) + + private fun isInsertSpacesInOneLineFunctionEnabled(project: Project) + = CodeStyleSettingsManager.getSettings(project).getCustomSettings(javaClass())!!.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD + } +} \ No newline at end of file diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinKeywordInsertHandler.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinKeywordInsertHandler.kt index 18cf15db4cf..121d55cc3f8 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinKeywordInsertHandler.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinKeywordInsertHandler.kt @@ -21,7 +21,7 @@ import com.intellij.codeInsight.completion.InsertionContext import com.intellij.codeInsight.lookup.LookupElement import org.jetbrains.kotlin.lexer.JetTokens.* -public object KotlinKeywordInsertHandler : InsertHandler { +object KotlinKeywordInsertHandler : InsertHandler { private val NO_SPACE_AFTER = listOf(THIS_KEYWORD, SUPER_KEYWORD, FOR_KEYWORD, diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinPropertyInsertHandler.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinPropertyInsertHandler.kt new file mode 100644 index 00000000000..66e37667d40 --- /dev/null +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinPropertyInsertHandler.kt @@ -0,0 +1,47 @@ +/* + * 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.handlers + +import com.intellij.codeInsight.completion.InsertionContext +import com.intellij.codeInsight.lookup.Lookup +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.psi.PsiDocumentManager + +object KotlinPropertyInsertHandler : KotlinCallableInsertHandler() { + public override fun handleInsert(context: InsertionContext, item: LookupElement) { + super.handleInsert(context, item) + + if (context.getCompletionChar() == Lookup.REPLACE_SELECT_CHAR) { + deleteEmptyParenthesis(context) + } + } + + private fun deleteEmptyParenthesis(context: InsertionContext) { + val psiDocumentManager = PsiDocumentManager.getInstance(context.getProject()) + psiDocumentManager.commitAllDocuments() + psiDocumentManager.doPostponedOperationsAndUnblockDocument(context.getDocument()) + + val offset = context.getTailOffset() + val document = context.getDocument() + val chars = document.getCharsSequence() + + val lParenOffset = chars.indexOfSkippingSpace('(', offset) ?: return + val rParenOffset = chars.indexOfSkippingSpace(')', lParenOffset + 1) ?: return + + document.deleteString(offset, rParenOffset + 1) + } +} \ No newline at end of file