Minor: Move around some functions

This commit is contained in:
Alexey Sedunov
2015-10-01 16:05:04 +03:00
parent 84008e9381
commit 3c14bedc04
4 changed files with 163 additions and 121 deletions
@@ -18,14 +18,16 @@ package org.jetbrains.kotlin.idea.quickfix
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.ScrollType import com.intellij.openapi.editor.ScrollType
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.SmartPointerManager import com.intellij.psi.SmartPointerManager
import org.jetbrains.kotlin.psi.JetBlockExpression import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.psi.JetDeclarationWithBody import com.intellij.util.SmartList
import org.jetbrains.kotlin.psi.JetProperty import org.jetbrains.kotlin.idea.util.ShortenReferences
import org.jetbrains.kotlin.psi.JetWithExpressionInitializer import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.siblings import org.jetbrains.kotlin.psi.psiUtil.siblings
public fun moveCaretIntoGeneratedElement(editor: Editor, element: PsiElement) { public fun moveCaretIntoGeneratedElement(editor: Editor, element: PsiElement) {
@@ -96,3 +98,85 @@ public fun Editor.moveCaret(offset: Int, scrollType: ScrollType = ScrollType.REL
getCaretModel().moveToOffset(offset) getCaretModel().moveToOffset(offset)
getScrollingModel().scrollToCaret(scrollType) 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 <T : JetDeclaration> generateMembers(
editor: Editor,
classOrObject: JetClassOrObject,
generators: Collection<() -> T>
): List<T> {
val insertedMembers = SmartList<T>()
return runWriteAction<List<T>> {
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 <T : JetDeclaration> generateMember(editor: Editor, classOrObject: JetClassOrObject, declaration: T): T {
return generateMembers(editor, classOrObject, listOf({ declaration })).single()
}
@@ -22,20 +22,14 @@ import com.intellij.lang.LanguageCodeInsightActionHandler
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.DialogWrapper import com.intellij.openapi.ui.DialogWrapper
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile 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.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.quickfix.moveCaretIntoGeneratedElement import org.jetbrains.kotlin.idea.quickfix.generateMembers
import org.jetbrains.kotlin.idea.util.ShortenReferences import org.jetbrains.kotlin.psi.JetClassOrObject
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import java.util.*
public abstract class OverrideImplementMembersHandler : LanguageCodeInsightActionHandler { public abstract class OverrideImplementMembersHandler : LanguageCodeInsightActionHandler {
@@ -95,75 +89,8 @@ public abstract class OverrideImplementMembersHandler : LanguageCodeInsightActio
companion object { companion object {
public fun generateMembers(editor: Editor, classOrObject: JetClassOrObject, selectedElements: Collection<OverrideMemberChooserObject>) { public fun generateMembers(editor: Editor, classOrObject: JetClassOrObject, selectedElements: Collection<OverrideMemberChooserObject>) {
runWriteAction { val project = classOrObject.project
if (selectedElements.isEmpty()) return@runWriteAction generateMembers(editor, classOrObject, selectedElements.map { chooser -> { chooser.generateMember(project) } })
val body = classOrObject.getOrCreateBody()
var afterAnchor = findInsertAfterAnchor(editor, body) ?: return@runWriteAction
var firstGenerated: PsiElement? = null
val project = classOrObject.project
val insertedMembers = ArrayList<JetCallableDeclaration>()
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
} }
} }
} }
@@ -927,46 +927,15 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
} }
private fun setupEditor(declaration: JetNamedDeclaration) { private fun setupEditor(declaration: JetNamedDeclaration) {
val caretModel = containingFileEditor.getCaretModel() if (declaration is JetProperty && !declaration.hasInitializer() && containingElement is JetBlockExpression) {
val selectionModel = containingFileEditor.getSelectionModel() val defaultValueType = typeCandidates[callableInfo.returnTypeInfo]!!.firstOrNull()?.theType
val defaultValue = defaultValueType?.let { CodeInsightUtils.defaultInitializer(it) } ?: "null"
if (declaration is JetSecondaryConstructor) { val initializer = declaration.setInitializer(JetPsiFactory(declaration).createExpression(defaultValue))!!
caretModel.moveToOffset(declaration.getConstructorKeyword().endOffset) val range = initializer.getTextRange()
containingFileEditor.getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset())
return
} }
else { setupEditorSelection(containingFileEditor, declaration)
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)
} }
// build templates // build templates
@@ -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)
}