Reformat completion.handlers
This commit is contained in:
+5
-3
@@ -21,14 +21,15 @@ 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.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
|
||||
object CastReceiverInsertHandler {
|
||||
fun postHandleInsert(context: InsertionContext, item: LookupElement) {
|
||||
val expression = PsiTreeUtil.findElementOfClassAtOffset(context.file, context.startOffset, KtSimpleNameExpression::class.java, false)
|
||||
val expression =
|
||||
PsiTreeUtil.findElementOfClassAtOffset(context.file, context.startOffset, KtSimpleNameExpression::class.java, false)
|
||||
val qualifiedExpression = PsiTreeUtil.getParentOfType(expression, KtQualifiedExpression::class.java, true)
|
||||
if (qualifiedExpression != null) {
|
||||
val receiver = qualifiedExpression.receiverExpression
|
||||
@@ -36,7 +37,8 @@ object CastReceiverInsertHandler {
|
||||
val descriptor = (item.`object` as? DeclarationLookupObject)?.descriptor as CallableDescriptor
|
||||
val project = context.project
|
||||
|
||||
val thisObj = if (descriptor.extensionReceiverParameter != null) descriptor.extensionReceiverParameter else descriptor.dispatchReceiverParameter
|
||||
val thisObj =
|
||||
if (descriptor.extensionReceiverParameter != null) descriptor.extensionReceiverParameter else descriptor.dispatchReceiverParameter
|
||||
val fqName = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(thisObj!!.type.constructor.declarationDescriptor!!)
|
||||
|
||||
val parentCast = KtPsiFactory(project).createExpression("(expr as $fqName)") as KtParenthesizedExpression
|
||||
|
||||
+8
-5
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
|
||||
abstract class KotlinCallableInsertHandler(val callType: CallType<*>) : BaseDeclarationInsertHandler() {
|
||||
companion object {
|
||||
private val shortenReferences = ShortenReferences({ ShortenReferences.Options.DEFAULT.copy(dropBracesInStringTemplates = false)})
|
||||
private val shortenReferences = ShortenReferences({ ShortenReferences.Options.DEFAULT.copy(dropBracesInStringTemplates = false) })
|
||||
}
|
||||
|
||||
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||
@@ -41,7 +41,7 @@ abstract class KotlinCallableInsertHandler(val callType: CallType<*>) : BaseDecl
|
||||
addImport(context, item)
|
||||
}
|
||||
|
||||
private fun addImport(context : InsertionContext, item : LookupElement) {
|
||||
private fun addImport(context: InsertionContext, item: LookupElement) {
|
||||
val psiDocumentManager = PsiDocumentManager.getInstance(context.project)
|
||||
psiDocumentManager.commitAllDocuments()
|
||||
|
||||
@@ -53,11 +53,14 @@ abstract class KotlinCallableInsertHandler(val callType: CallType<*>) : BaseDecl
|
||||
if (DescriptorUtils.isTopLevelDeclaration(descriptor) && !descriptor.isArtificialImportAliasedDescriptor) {
|
||||
ImportInsertHelper.getInstance(context.project).importDescriptor(file, descriptor)
|
||||
}
|
||||
}
|
||||
else if (callType == CallType.DEFAULT) {
|
||||
} else if (callType == CallType.DEFAULT) {
|
||||
if (descriptor.isArtificialImportAliasedDescriptor) return
|
||||
val fqName = descriptor.importableFqName ?: return
|
||||
context.document.replaceString(context.startOffset, context.tailOffset, fqName.render() + " ") // insert space after for correct parsing
|
||||
context.document.replaceString(
|
||||
context.startOffset,
|
||||
context.tailOffset,
|
||||
fqName.render() + " "
|
||||
) // insert space after for correct parsing
|
||||
|
||||
psiDocumentManager.commitAllDocuments()
|
||||
|
||||
|
||||
+5
-7
@@ -25,10 +25,10 @@ import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.completion.isAfterDot
|
||||
import org.jetbrains.kotlin.idea.completion.isArtificialImportAliasedDescriptor
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
|
||||
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
@@ -53,7 +53,7 @@ object KotlinClassifierInsertHandler : BaseDeclarationInsertHandler() {
|
||||
|
||||
val lookupObject = item.`object` as DeclarationLookupObject
|
||||
if (lookupObject.descriptor?.isArtificialImportAliasedDescriptor == true) return // never need to insert import or use qualified name for import-aliased class
|
||||
|
||||
|
||||
val qualifiedName = qualifiedName(lookupObject)
|
||||
|
||||
// first try to resolve short name for faster handling
|
||||
@@ -62,7 +62,7 @@ object KotlinClassifierInsertHandler : BaseDeclarationInsertHandler() {
|
||||
if (nameRef != null) {
|
||||
val bindingContext = nameRef.analyze(BodyResolveMode.PARTIAL)
|
||||
val target = bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, nameRef]
|
||||
?: bindingContext[BindingContext.REFERENCE_TARGET, nameRef] as? ClassDescriptor
|
||||
?: bindingContext[BindingContext.REFERENCE_TARGET, nameRef] as? ClassDescriptor
|
||||
if (target != null && IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(target) == qualifiedName) return
|
||||
}
|
||||
|
||||
@@ -71,8 +71,7 @@ object KotlinClassifierInsertHandler : BaseDeclarationInsertHandler() {
|
||||
// we insert space so that any preceding spaces inserted by formatter on reference shortening are deleted
|
||||
// (but not for annotations where spaces are not allowed after @)
|
||||
if (isAnnotation) "" else " "
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
"$;val v:" // if we have no reference in the current context we have a more complicated prefix to get one
|
||||
}
|
||||
val tempSuffix = ".xxx" // we add "xxx" after dot because of KT-9606
|
||||
@@ -99,8 +98,7 @@ object KotlinClassifierInsertHandler : BaseDeclarationInsertHandler() {
|
||||
private fun qualifiedName(lookupObject: DeclarationLookupObject): String {
|
||||
return if (lookupObject.descriptor != null) {
|
||||
IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(lookupObject.descriptor as ClassifierDescriptor)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val qualifiedName = (lookupObject.psiElement as PsiClass).qualifiedName!!
|
||||
if (FqNameUnsafe.isValid(qualifiedName)) FqNameUnsafe(qualifiedName).render() else qualifiedName
|
||||
}
|
||||
|
||||
+30
-25
@@ -39,12 +39,12 @@ class GenerateLambdaInfo(val lambdaType: KotlinType, val explicitParameters: Boo
|
||||
sealed class KotlinFunctionInsertHandler(callType: CallType<*>) : KotlinCallableInsertHandler(callType) {
|
||||
|
||||
class Normal(
|
||||
callType: CallType<*>,
|
||||
val inputTypeArguments: Boolean,
|
||||
val inputValueArguments: Boolean,
|
||||
val argumentText: String = "",
|
||||
val lambdaInfo: GenerateLambdaInfo? = null,
|
||||
val argumentsOnly: Boolean = false
|
||||
callType: CallType<*>,
|
||||
val inputTypeArguments: Boolean,
|
||||
val inputValueArguments: Boolean,
|
||||
val argumentText: String = "",
|
||||
val lambdaInfo: GenerateLambdaInfo? = null,
|
||||
val argumentsOnly: Boolean = false
|
||||
) : KotlinFunctionInsertHandler(callType) {
|
||||
init {
|
||||
if (lambdaInfo != null) {
|
||||
@@ -54,12 +54,12 @@ sealed class KotlinFunctionInsertHandler(callType: CallType<*>) : KotlinCallable
|
||||
|
||||
//TODO: add 'data' or special annotation when supported
|
||||
fun copy(
|
||||
callType: CallType<*> = this.callType,
|
||||
inputTypeArguments: Boolean = this.inputTypeArguments,
|
||||
inputValueArguments: Boolean = this.inputValueArguments,
|
||||
argumentText: String = this.argumentText,
|
||||
lambdaInfo: GenerateLambdaInfo? = this.lambdaInfo,
|
||||
argumentsOnly: Boolean = this.argumentsOnly
|
||||
callType: CallType<*> = this.callType,
|
||||
inputTypeArguments: Boolean = this.inputTypeArguments,
|
||||
inputValueArguments: Boolean = this.inputValueArguments,
|
||||
argumentText: String = this.argumentText,
|
||||
lambdaInfo: GenerateLambdaInfo? = this.lambdaInfo,
|
||||
argumentsOnly: Boolean = this.argumentsOnly
|
||||
) = Normal(callType, inputTypeArguments, inputValueArguments, argumentText, lambdaInfo, argumentsOnly)
|
||||
|
||||
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||
@@ -81,7 +81,7 @@ sealed class KotlinFunctionInsertHandler(callType: CallType<*>) : KotlinCallable
|
||||
addArguments(context, element)
|
||||
}
|
||||
|
||||
private fun addArguments(context : InsertionContext, offsetElement : PsiElement) {
|
||||
private fun addArguments(context: InsertionContext, offsetElement: PsiElement) {
|
||||
val completionChar = context.completionChar
|
||||
if (completionChar == '(') { //TODO: more correct behavior related to braces type
|
||||
context.setAddCompletionChar(false)
|
||||
@@ -98,7 +98,8 @@ sealed class KotlinFunctionInsertHandler(callType: CallType<*>) : KotlinCallable
|
||||
val openingBracket = if (insertLambda) '{' else '('
|
||||
val closingBracket = if (insertLambda) '}' else ')'
|
||||
|
||||
var insertTypeArguments = inputTypeArguments && (completionChar == '\n' || completionChar == '\r' || completionChar == Lookup.REPLACE_SELECT_CHAR)
|
||||
var insertTypeArguments =
|
||||
inputTypeArguments && (completionChar == '\n' || completionChar == '\r' || completionChar == Lookup.REPLACE_SELECT_CHAR)
|
||||
|
||||
if (completionChar == Lookup.REPLACE_SELECT_CHAR) {
|
||||
val offset1 = chars.skipSpaces(offset)
|
||||
@@ -144,12 +145,10 @@ sealed class KotlinFunctionInsertHandler(callType: CallType<*>) : KotlinCallable
|
||||
if (isInsertSpacesInOneLineFunctionEnabled(project)) {
|
||||
document.insertString(offset, " { }")
|
||||
inBracketsShift = 1
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
document.insertString(offset, " {}")
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
document.insertString(offset, "()")
|
||||
}
|
||||
PsiDocumentManager.getInstance(project).commitDocument(document)
|
||||
@@ -160,8 +159,15 @@ sealed class KotlinFunctionInsertHandler(callType: CallType<*>) : KotlinCallable
|
||||
|
||||
if (insertLambda && lambdaInfo!!.explicitParameters) {
|
||||
val placeholderRange = TextRange(openingBracketOffset, closeBracketOffset!! + 1)
|
||||
val explicitParameterTypes = LambdaSignatureTemplates.explicitParameterTypesRequired(context.file as KtFile, placeholderRange, lambdaInfo.lambdaType)
|
||||
LambdaSignatureTemplates.insertTemplate(context, placeholderRange, lambdaInfo.lambdaType, explicitParameterTypes, signatureOnly = false)
|
||||
val explicitParameterTypes =
|
||||
LambdaSignatureTemplates.explicitParameterTypesRequired(context.file as KtFile, placeholderRange, lambdaInfo.lambdaType)
|
||||
LambdaSignatureTemplates.insertTemplate(
|
||||
context,
|
||||
placeholderRange,
|
||||
lambdaInfo.lambdaType,
|
||||
explicitParameterTypes,
|
||||
signatureOnly = false
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -176,8 +182,7 @@ sealed class KotlinFunctionInsertHandler(callType: CallType<*>) : KotlinCallable
|
||||
if (!insertLambda) {
|
||||
AutoPopupController.getInstance(project)?.autoPopupParameterInfo(editor, offsetElement)
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
editor.caretModel.moveToOffset(closeBracketOffset + 1)
|
||||
}
|
||||
}
|
||||
@@ -189,8 +194,8 @@ sealed class KotlinFunctionInsertHandler(callType: CallType<*>) : KotlinCallable
|
||||
return inputValueArguments || lambdaInfo != null
|
||||
}
|
||||
|
||||
private fun isInsertSpacesInOneLineFunctionEnabled(project: Project)
|
||||
= CodeStyleSettingsManager.getSettings(project).getCustomSettings(KotlinCodeStyleSettings::class.java)!!.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD
|
||||
private fun isInsertSpacesInOneLineFunctionEnabled(project: Project) =
|
||||
CodeStyleSettingsManager.getSettings(project).getCustomSettings(KotlinCodeStyleSettings::class.java)!!.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD
|
||||
}
|
||||
|
||||
object Infix : KotlinFunctionInsertHandler(CallType.INFIX) {
|
||||
@@ -205,7 +210,7 @@ sealed class KotlinFunctionInsertHandler(callType: CallType<*>) : KotlinCallable
|
||||
context.document.insertString(tailOffset, " ")
|
||||
context.editor.caretModel.moveToOffset(tailOffset + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class OnlyName(callType: CallType<*>) : KotlinFunctionInsertHandler(callType)
|
||||
|
||||
|
||||
+7
-5
@@ -27,10 +27,12 @@ import org.jetbrains.kotlin.idea.completion.KEEP_OLD_ARGUMENT_LIST_ON_TAB_KEY
|
||||
import org.jetbrains.kotlin.idea.completion.smart.SmartCompletion
|
||||
import org.jetbrains.kotlin.idea.completion.tryGetOffset
|
||||
|
||||
class WithTailInsertHandler(val tailText: String,
|
||||
val spaceBefore: Boolean,
|
||||
val spaceAfter: Boolean,
|
||||
val overwriteText: Boolean = true) : InsertHandler<LookupElement> {
|
||||
class WithTailInsertHandler(
|
||||
val tailText: String,
|
||||
val spaceBefore: Boolean,
|
||||
val spaceAfter: Boolean,
|
||||
val overwriteText: Boolean = true
|
||||
) : InsertHandler<LookupElement> {
|
||||
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||
item.handleInsert(context)
|
||||
postHandleInsert(context, item)
|
||||
@@ -49,7 +51,7 @@ class WithTailInsertHandler(val tailText: String,
|
||||
var tailOffset = context.tailOffset
|
||||
if (completionChar == Lookup.REPLACE_SELECT_CHAR && item.getUserData(KEEP_OLD_ARGUMENT_LIST_ON_TAB_KEY) != null) {
|
||||
context.offsetMap.tryGetOffset(SmartCompletion.OLD_ARGUMENTS_REPLACEMENT_OFFSET)
|
||||
?.let { tailOffset = it }
|
||||
?.let { tailOffset = it }
|
||||
}
|
||||
|
||||
val moveCaret = context.editor.caretModel.offset == tailOffset
|
||||
|
||||
+44
-36
@@ -90,21 +90,21 @@ fun CharSequence.indexOfSkippingSpace(c: Char, startIndex: Int): Int? {
|
||||
return null
|
||||
}
|
||||
|
||||
fun CharSequence.skipSpaces(index: Int): Int
|
||||
= (index..length - 1).firstOrNull { val c = this[it]; c != ' ' && c != '\t' } ?: this.length
|
||||
fun CharSequence.skipSpaces(index: Int): Int = (index..length - 1).firstOrNull { val c = this[it]; c != ' ' && c != '\t' } ?: this.length
|
||||
|
||||
fun CharSequence.skipSpacesAndLineBreaks(index: Int): Int
|
||||
= (index..length - 1).firstOrNull { val c = this[it]; c != ' ' && c != '\t' && c != '\n' && c != '\r' } ?: this.length
|
||||
fun CharSequence.skipSpacesAndLineBreaks(index: Int): Int =
|
||||
(index..length - 1).firstOrNull { val c = this[it]; c != ' ' && c != '\t' && c != '\n' && c != '\r' } ?: this.length
|
||||
|
||||
fun CharSequence.isCharAt(offset: Int, c: Char) = offset < length && this[offset] == c
|
||||
|
||||
fun Document.isTextAt(offset: Int, text: String) = offset + text.length <= textLength && getText(TextRange(offset, offset + text.length)) == text
|
||||
fun Document.isTextAt(offset: Int, text: String) =
|
||||
offset + text.length <= textLength && getText(TextRange(offset, offset + text.length)) == text
|
||||
|
||||
fun createKeywordConstructLookupElement(
|
||||
project: Project,
|
||||
keyword: String,
|
||||
fileTextToReformat: String,
|
||||
trimSpacesAroundCaret: Boolean = false
|
||||
project: Project,
|
||||
keyword: String,
|
||||
fileTextToReformat: String,
|
||||
trimSpacesAroundCaret: Boolean = false
|
||||
): LookupElement {
|
||||
val file = KtPsiFactory(project).createFile(fileTextToReformat)
|
||||
CodeStyleManager.getInstance(project).reformat(file)
|
||||
@@ -133,46 +133,54 @@ fun createKeywordConstructLookupElement(
|
||||
tailAfterCaret = tailAfterCaret.unindent(indent)
|
||||
|
||||
val tailText = (if (tailBeforeCaret.contains('\n')) tailBeforeCaret.replace("\n", "").trimEnd() else tailBeforeCaret) +
|
||||
"..." +
|
||||
(if (tailAfterCaret.contains('\n')) tailAfterCaret.replace("\n", "").trimStart() else tailAfterCaret)
|
||||
"..." +
|
||||
(if (tailAfterCaret.contains('\n')) tailAfterCaret.replace("\n", "").trimStart() else tailAfterCaret)
|
||||
|
||||
return LookupElementBuilder.create(KeywordLookupObject(), keyword)
|
||||
.bold()
|
||||
.withTailText(tailText)
|
||||
.withInsertHandler { insertionContext, _ ->
|
||||
if (insertionContext.completionChar == Lookup.NORMAL_SELECT_CHAR ||
|
||||
insertionContext.completionChar == Lookup.REPLACE_SELECT_CHAR ||
|
||||
insertionContext.completionChar == Lookup.AUTO_INSERT_SELECT_CHAR) {
|
||||
.bold()
|
||||
.withTailText(tailText)
|
||||
.withInsertHandler { insertionContext, _ ->
|
||||
if (insertionContext.completionChar == Lookup.NORMAL_SELECT_CHAR ||
|
||||
insertionContext.completionChar == Lookup.REPLACE_SELECT_CHAR ||
|
||||
insertionContext.completionChar == Lookup.AUTO_INSERT_SELECT_CHAR
|
||||
) {
|
||||
|
||||
val offset = insertionContext.tailOffset
|
||||
val newIndent = detectIndent(insertionContext.document.charsSequence, offset - keyword.length)
|
||||
val offset = insertionContext.tailOffset
|
||||
val newIndent = detectIndent(insertionContext.document.charsSequence, offset - keyword.length)
|
||||
|
||||
val beforeCaret = tailBeforeCaret.indentLinesAfterFirst(newIndent)
|
||||
val afterCaret = tailAfterCaret.indentLinesAfterFirst(newIndent)
|
||||
val beforeCaret = tailBeforeCaret.indentLinesAfterFirst(newIndent)
|
||||
val afterCaret = tailAfterCaret.indentLinesAfterFirst(newIndent)
|
||||
|
||||
val element = insertionContext.file.findElementAt(offset)
|
||||
val element = insertionContext.file.findElementAt(offset)
|
||||
|
||||
val sibling = when {
|
||||
element !is PsiWhiteSpace -> element
|
||||
element.textContains('\n') -> null
|
||||
else -> element.getNextSiblingIgnoringWhitespace(true)
|
||||
}
|
||||
val sibling = when {
|
||||
element !is PsiWhiteSpace -> element
|
||||
element.textContains('\n') -> null
|
||||
else -> element.getNextSiblingIgnoringWhitespace(true)
|
||||
}
|
||||
|
||||
if (sibling != null && beforeCaret.trimStart().startsWith(insertionContext.document.getText(TextRange.from(sibling.startOffset, 1)))) {
|
||||
insertionContext.editor.moveCaret(sibling.startOffset + 1)
|
||||
}
|
||||
else {
|
||||
insertionContext.document.insertString(offset, beforeCaret + afterCaret)
|
||||
insertionContext.editor.moveCaret(offset + beforeCaret.length)
|
||||
}
|
||||
if (sibling != null && beforeCaret.trimStart().startsWith(
|
||||
insertionContext.document.getText(
|
||||
TextRange.from(
|
||||
sibling.startOffset,
|
||||
1
|
||||
)
|
||||
)
|
||||
)
|
||||
) {
|
||||
insertionContext.editor.moveCaret(sibling.startOffset + 1)
|
||||
} else {
|
||||
insertionContext.document.insertString(offset, beforeCaret + afterCaret)
|
||||
insertionContext.editor.moveCaret(offset + beforeCaret.length)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun detectIndent(text: CharSequence, offset: Int): String {
|
||||
return text.substring(0, offset)
|
||||
.substringAfterLast('\n')
|
||||
.takeWhile(Char::isWhitespace)
|
||||
.substringAfterLast('\n')
|
||||
.takeWhile(Char::isWhitespace)
|
||||
}
|
||||
|
||||
private fun String.indentLinesAfterFirst(indent: String): String {
|
||||
|
||||
Reference in New Issue
Block a user