Minor: Move around some functions
This commit is contained in:
@@ -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()
|
||||
}
|
||||
+5
-78
@@ -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) } })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-39
@@ -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
|
||||
|
||||
+62
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user