From 3c14bedc04fa13f5d68df2038119267a5adfcea6 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 1 Oct 2015 16:05:04 +0300 Subject: [PATCH] Minor: Move around some functions --- .../kotlin/idea/quickfix/generateUtil.kt | 92 ++++++++++++++++++- .../OverrideImplementMembersHandler.kt | 83 +---------------- .../callableBuilder/CallableBuilder.kt | 47 ++-------- .../callableBuilder/generationUtils.kt | 62 +++++++++++++ 4 files changed, 163 insertions(+), 121 deletions(-) create mode 100644 idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/generationUtils.kt diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/quickfix/generateUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/quickfix/generateUtil.kt index 0f83817f9f7..cc7938b30dc 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/quickfix/generateUtil.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/quickfix/generateUtil.kt @@ -18,14 +18,16 @@ package org.jetbrains.kotlin.idea.quickfix import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.ScrollType +import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.SmartPointerManager -import org.jetbrains.kotlin.psi.JetBlockExpression -import org.jetbrains.kotlin.psi.JetDeclarationWithBody -import org.jetbrains.kotlin.psi.JetProperty -import org.jetbrains.kotlin.psi.JetWithExpressionInitializer +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.util.SmartList +import org.jetbrains.kotlin.idea.util.ShortenReferences +import org.jetbrains.kotlin.idea.util.application.runWriteAction +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.siblings public fun moveCaretIntoGeneratedElement(editor: Editor, element: PsiElement) { @@ -96,3 +98,85 @@ public fun Editor.moveCaret(offset: Int, scrollType: ScrollType = ScrollType.REL getCaretModel().moveToOffset(offset) getScrollingModel().scrollToCaret(scrollType) } + +private fun findInsertAfterAnchor(editor: Editor, body: JetClassBody): PsiElement? { + val afterAnchor = body.lBrace ?: return null + + val offset = editor.caretModel.offset + val offsetCursorElement = PsiTreeUtil.findFirstParent(body.containingFile.findElementAt(offset)) { + it.parent == body + } + + if (offsetCursorElement is PsiWhiteSpace) { + return removeAfterOffset(offset, offsetCursorElement) + } + + if (offsetCursorElement != null && offsetCursorElement != body.rBrace) { + return offsetCursorElement + } + + return afterAnchor +} + +private fun removeAfterOffset(offset: Int, whiteSpace: PsiWhiteSpace): PsiElement { + val spaceNode = whiteSpace.node + if (spaceNode.textRange.contains(offset)) { + var beforeWhiteSpaceText = spaceNode.text.substring(0, offset - spaceNode.startOffset) + if (!StringUtil.containsLineBreak(beforeWhiteSpaceText)) { + // Prevent insertion on same line + beforeWhiteSpaceText += "\n" + } + + val factory = JetPsiFactory(whiteSpace.project) + + val insertAfter = whiteSpace.prevSibling + whiteSpace.delete() + + val beforeSpace = factory.createWhiteSpace(beforeWhiteSpaceText) + insertAfter.parent.addAfter(beforeSpace, insertAfter) + + return insertAfter.nextSibling + } + + return whiteSpace +} + +public fun generateMembers( + editor: Editor, + classOrObject: JetClassOrObject, + generators: Collection<() -> T> +): List { + val insertedMembers = SmartList() + return runWriteAction> { + if (generators.isEmpty()) return@runWriteAction emptyList() + + val body = classOrObject.getOrCreateBody() + + var afterAnchor = findInsertAfterAnchor(editor, body) ?: return@runWriteAction emptyList() + + var firstGenerated: PsiElement? = null + + for (generator in generators) { + val member = generator() + @Suppress("UNCHECKED_CAST") + val added = body.addAfter(member, afterAnchor) as T + + if (firstGenerated == null) { + firstGenerated = added + } + + afterAnchor = added + insertedMembers.add(added) + } + + ShortenReferences.DEFAULT.process(insertedMembers) + + moveCaretIntoGeneratedElement(editor, firstGenerated!!) + + insertedMembers + } +} + +public fun generateMember(editor: Editor, classOrObject: JetClassOrObject, declaration: T): T { + return generateMembers(editor, classOrObject, listOf({ declaration })).single() +} \ No newline at end of file diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideImplementMembersHandler.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideImplementMembersHandler.kt index 165f8d077cc..3eb9bba7102 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideImplementMembersHandler.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideImplementMembersHandler.kt @@ -22,20 +22,14 @@ import com.intellij.lang.LanguageCodeInsightActionHandler import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.openapi.ui.DialogWrapper -import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.PsiDocumentManager -import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile -import com.intellij.psi.PsiWhiteSpace -import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor -import org.jetbrains.kotlin.idea.quickfix.moveCaretIntoGeneratedElement -import org.jetbrains.kotlin.idea.util.ShortenReferences -import org.jetbrains.kotlin.idea.util.application.runWriteAction -import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.idea.quickfix.generateMembers +import org.jetbrains.kotlin.psi.JetClassOrObject +import org.jetbrains.kotlin.psi.JetFile import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType -import java.util.* public abstract class OverrideImplementMembersHandler : LanguageCodeInsightActionHandler { @@ -95,75 +89,8 @@ public abstract class OverrideImplementMembersHandler : LanguageCodeInsightActio companion object { public fun generateMembers(editor: Editor, classOrObject: JetClassOrObject, selectedElements: Collection) { - runWriteAction { - if (selectedElements.isEmpty()) return@runWriteAction - - val body = classOrObject.getOrCreateBody() - - var afterAnchor = findInsertAfterAnchor(editor, body) ?: return@runWriteAction - - var firstGenerated: PsiElement? = null - - val project = classOrObject.project - val insertedMembers = ArrayList() - for (memberObject in selectedElements) { - val member = memberObject.generateMember(project) - val added = body.addAfter(member, afterAnchor) as JetCallableDeclaration - - if (firstGenerated == null) { - firstGenerated = added - } - - afterAnchor = added - insertedMembers.add(added) - } - - ShortenReferences.DEFAULT.process(insertedMembers) - - moveCaretIntoGeneratedElement(editor, firstGenerated!!) - } - } - - private fun findInsertAfterAnchor(editor: Editor, body: JetClassBody): PsiElement? { - val afterAnchor = body.lBrace ?: return null - - val offset = editor.caretModel.offset - val offsetCursorElement = PsiTreeUtil.findFirstParent(body.containingFile.findElementAt(offset)) { - it.parent == body - } - - if (offsetCursorElement is PsiWhiteSpace) { - return removeAfterOffset(offset, offsetCursorElement) - } - - if (offsetCursorElement != null && offsetCursorElement != body.rBrace) { - return offsetCursorElement - } - - return afterAnchor - } - - private fun removeAfterOffset(offset: Int, whiteSpace: PsiWhiteSpace): PsiElement { - val spaceNode = whiteSpace.node - if (spaceNode.textRange.contains(offset)) { - var beforeWhiteSpaceText = spaceNode.text.substring(0, offset - spaceNode.startOffset) - if (!StringUtil.containsLineBreak(beforeWhiteSpaceText)) { - // Prevent insertion on same line - beforeWhiteSpaceText += "\n" - } - - val factory = JetPsiFactory(whiteSpace.project) - - val insertAfter = whiteSpace.prevSibling - whiteSpace.delete() - - val beforeSpace = factory.createWhiteSpace(beforeWhiteSpaceText) - insertAfter.parent.addAfter(beforeSpace, insertAfter) - - return insertAfter.nextSibling - } - - return whiteSpace + val project = classOrObject.project + generateMembers(editor, classOrObject, selectedElements.map { chooser -> { chooser.generateMember(project) } }) } } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt index 2d6dbe3f5ed..b60e6cda548 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt @@ -927,46 +927,15 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { } private fun setupEditor(declaration: JetNamedDeclaration) { - val caretModel = containingFileEditor.getCaretModel() - val selectionModel = containingFileEditor.getSelectionModel() - - if (declaration is JetSecondaryConstructor) { - caretModel.moveToOffset(declaration.getConstructorKeyword().endOffset) + if (declaration is JetProperty && !declaration.hasInitializer() && containingElement is JetBlockExpression) { + val defaultValueType = typeCandidates[callableInfo.returnTypeInfo]!!.firstOrNull()?.theType + val defaultValue = defaultValueType?.let { CodeInsightUtils.defaultInitializer(it) } ?: "null" + val initializer = declaration.setInitializer(JetPsiFactory(declaration).createExpression(defaultValue))!! + val range = initializer.getTextRange() + containingFileEditor.getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset()) + return } - else { - caretModel.moveToOffset(declaration.getNameIdentifier()!!.endOffset) - } - - fun positionBetween(left: PsiElement, right: PsiElement) { - val from = left.siblings(withItself = false, forward = true).firstOrNull { it !is PsiWhiteSpace } ?: return - val to = right.siblings(withItself = false, forward = false).firstOrNull { it !is PsiWhiteSpace } ?: return - val startOffset = from.startOffset - val endOffset = to.endOffset - caretModel.moveToOffset(endOffset) - selectionModel.setSelection(startOffset, endOffset) - } - - when (declaration) { - is JetNamedFunction, is JetSecondaryConstructor -> { - ((declaration as JetFunction).getBodyExpression() as? JetBlockExpression)?.let { - positionBetween(it.getLBrace()!!, it.getRBrace()!!) - } - } - is JetClassOrObject -> { - caretModel.moveToOffset(declaration.startOffset) - } - is JetProperty -> { - if (!declaration.hasInitializer() && containingElement is JetBlockExpression) { - val defaultValueType = typeCandidates[callableInfo.returnTypeInfo]!!.firstOrNull()?.theType - val defaultValue = defaultValueType?.let {CodeInsightUtils.defaultInitializer(it) } ?: "null" - val initializer = declaration.setInitializer(JetPsiFactory(declaration).createExpression(defaultValue))!! - val range = initializer.getTextRange() - selectionModel.setSelection(range.getStartOffset(), range.getEndOffset()) - } - caretModel.moveToOffset(declaration.endOffset) - } - } - containingFileEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE) + setupEditorSelection(containingFileEditor, declaration) } // build templates diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/generationUtils.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/generationUtils.kt new file mode 100644 index 00000000000..6b311b94e44 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/generationUtils.kt @@ -0,0 +1,62 @@ +/* + * 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.quickfix.createFromUsage.callableBuilder + +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.editor.ScrollType +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiWhiteSpace +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.endOffset +import org.jetbrains.kotlin.psi.psiUtil.siblings +import org.jetbrains.kotlin.psi.psiUtil.startOffset + +public fun setupEditorSelection(editor: Editor, declaration: JetNamedDeclaration) { + val caretModel = editor.caretModel + val selectionModel = editor.selectionModel + + if (declaration is JetSecondaryConstructor) { + caretModel.moveToOffset(declaration.getConstructorKeyword().endOffset) + } + else { + caretModel.moveToOffset(declaration.nameIdentifier!!.endOffset) + } + + fun positionBetween(left: PsiElement, right: PsiElement) { + val from = left.siblings(withItself = false, forward = true).firstOrNull { it !is PsiWhiteSpace } ?: return + val to = right.siblings(withItself = false, forward = false).firstOrNull { it !is PsiWhiteSpace } ?: return + val startOffset = from.startOffset + val endOffset = to.endOffset + caretModel.moveToOffset(endOffset) + selectionModel.setSelection(startOffset, endOffset) + } + + when (declaration) { + is JetNamedFunction, is JetSecondaryConstructor -> { + ((declaration as JetFunction).bodyExpression as? JetBlockExpression)?.let { + positionBetween(it.lBrace!!, it.rBrace!!) + } + } + is JetClassOrObject -> { + caretModel.moveToOffset(declaration.startOffset) + } + is JetProperty -> { + caretModel.moveToOffset(declaration.endOffset) + } + } + editor.scrollingModel.scrollToCaret(ScrollType.RELATIVE) +}