Moved classes into separate files

This commit is contained in:
Valentin Kipyatkov
2015-05-14 19:34:59 +03:00
parent 858adfb2db
commit 7641c3cb84
6 changed files with 280 additions and 208 deletions
@@ -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<JetSimpleNameExpression>(), false)
val qualifiedExpression = PsiTreeUtil.getParentOfType(expression, javaClass<JetQualifiedExpression>(), 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())
}
}
}
@@ -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<JetImportDirective>() != 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<JetCodeStyleSettings>())!!.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<JetSimpleNameExpression>(), false)
val qualifiedExpression = PsiTreeUtil.getParentOfType(expression, javaClass<JetQualifiedExpression>(), 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())
}
}
}
@@ -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)
@@ -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<JetImportDirective>() != 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<JetCodeStyleSettings>())!!.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD
}
}
@@ -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<LookupElement> {
object KotlinKeywordInsertHandler : InsertHandler<LookupElement> {
private val NO_SPACE_AFTER = listOf(THIS_KEYWORD,
SUPER_KEYWORD,
FOR_KEYWORD,
@@ -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)
}
}