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.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 <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.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<OverrideMemberChooserObject>) {
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<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
val project = classOrObject.project
generateMembers(editor, classOrObject, selectedElements.map { chooser -> { chooser.generateMember(project) } })
}
}
}
@@ -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
@@ -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)
}