Refactoring: Move selectElements() function to introduceUtil.kt

This commit is contained in:
Alexey Sedunov
2015-02-25 11:23:30 +03:00
parent 997c7f9d6c
commit 0a6010ff9d
3 changed files with 132 additions and 114 deletions
@@ -22,17 +22,10 @@ import com.intellij.psi.PsiFile
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import com.intellij.openapi.project.Project
import com.intellij.openapi.editor.ScrollType
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.idea.refactoring.JetRefactoringUtil
import com.intellij.refactoring.HelpID
import org.jetbrains.kotlin.idea.refactoring.JetRefactoringBundle
import org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.ui.KotlinExtractFunctionDialog
import org.jetbrains.kotlin.psi.JetFile
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.psi.JetElement
import com.intellij.openapi.application.ApplicationManager
import org.jetbrains.kotlin.psi.psiUtil.getOutermostParentContainedIn
import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.psi.JetBlockExpression
@@ -46,9 +39,9 @@ import com.intellij.ui.awt.RelativePoint
import com.intellij.openapi.ui.popup.Balloon.Position
import org.jetbrains.kotlin.psi.JetFunctionLiteral
import org.jetbrains.kotlin.idea.util.psi.patternMatching.toRange
import org.jetbrains.kotlin.idea.refactoring.chooseContainerElementIfNecessary
import org.jetbrains.kotlin.idea.refactoring.getExtractionContainers
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.*
import org.jetbrains.kotlin.idea.refactoring.introduce.*
public open class ExtractKotlinFunctionHandlerHelper {
open fun adjustExtractionData(data: ExtractionData): ExtractionData = data
@@ -112,7 +105,7 @@ public class ExtractKotlinFunctionHandler(
val message = analysisResult.messages.map { it.renderMessage() }.joinToString("\n")
when (analysisResult.status) {
Status.CRITICAL_ERROR -> {
showErrorHint(project, editor, message)
showErrorHint(project, editor, message, EXTRACT_FUNCTION)
}
Status.NON_CRITICAL_ERROR -> {
@@ -141,12 +134,19 @@ public class ExtractKotlinFunctionHandler(
}
}
fun selectElements(editor: Editor, file: PsiFile, continuation: (elements: List<PsiElement>, targetSibling: PsiElement) -> Unit) {
selectElements(
EXTRACT_FUNCTION,
editor,
file,
{(elements, parent) -> parent.getExtractionContainers(elements.size() == 1, allContainersEnabled) },
continuation
)
}
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
if (file !is JetFile) return
selectElements(editor, file, allContainersEnabled) { (elements, targetSibling) ->
doInvoke(editor, file, elements, targetSibling)
}
selectElements(editor, file) { (elements, targetSibling) -> doInvoke(editor, file, elements, targetSibling) }
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext?) {
@@ -154,92 +154,4 @@ public class ExtractKotlinFunctionHandler(
}
}
private val EXTRACT_FUNCTION: String = JetRefactoringBundle.message("extract.function")!!
private fun showErrorHint(project: Project, editor: Editor, message: String) {
CodeInsightUtils.showErrorHint(project, editor, message, EXTRACT_FUNCTION, HelpID.EXTRACT_METHOD)
}
private fun showErrorHintByKey(project: Project, editor: Editor, key: String) {
showErrorHint(project, editor, JetRefactoringBundle.message(key)!!)
}
fun selectElements(
editor: Editor,
file: PsiFile,
allContainersEnabled: Boolean = false,
continuation: (elements: List<PsiElement>, targetSibling: PsiElement) -> Unit
) {
fun noExpressionError() {
showErrorHintByKey(file.getProject(), editor, "cannot.refactor.no.expression")
}
fun noContainerError() {
showErrorHintByKey(file.getProject(), editor, "cannot.refactor.no.container")
}
fun onSelectionComplete(parent: PsiElement, elements: List<PsiElement>, targetContainer: JetElement) {
if (parent == targetContainer) {
continuation(elements, elements.first())
return
}
val outermostParent = parent.getOutermostParentContainedIn(targetContainer)
if (outermostParent == null) {
noContainerError()
return
}
continuation(elements, outermostParent)
}
fun selectTargetContainer(elements: List<PsiElement>) {
val parent = PsiTreeUtil.findCommonParent(elements)
?: throw AssertionError("Should have at least one parent: ${elements.joinToString("\n")}")
val containers = parent.getExtractionContainers(elements.size() == 1, allContainersEnabled)
if (containers.isEmpty()) {
noContainerError()
return
}
chooseContainerElementIfNecessary(
containers,
editor,
"Select target code block",
true,
{ it },
{ onSelectionComplete(parent, elements, it) }
)
}
fun selectMultipleExpressions() {
val startOffset = editor.getSelectionModel().getSelectionStart()
val endOffset = editor.getSelectionModel().getSelectionEnd()
val elements = CodeInsightUtils.findStatements(file, startOffset, endOffset)
if (elements.isEmpty()) {
noExpressionError()
return
}
selectTargetContainer(elements.toList())
}
fun selectSingleExpression() {
JetRefactoringUtil.selectExpression(editor, file, false) { expr ->
if (expr != null) {
selectTargetContainer(listOf(expr))
}
else {
if (!editor.getSelectionModel().hasSelection()) {
editor.getSelectionModel().selectLineAtCaret()
}
selectMultipleExpressions()
}
}
}
editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE)
selectSingleExpression()
}
private val EXTRACT_FUNCTION: String = JetRefactoringBundle.message("extract.function")
@@ -0,0 +1,106 @@
/*
* 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.refactoring.introduce
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.idea.refactoring.*
import com.intellij.openapi.editor.*
import com.intellij.psi.*
import com.intellij.psi.util.*
import org.jetbrains.kotlin.idea.codeInsight.*
import com.intellij.openapi.project.*
fun showErrorHint(project: Project, editor: Editor, message: String, title: String) {
CodeInsightUtils.showErrorHint(project, editor, message, title, null)
}
fun selectElements(
operationName: String,
editor: Editor,
file: PsiFile,
getContainers: (elements: List<PsiElement>, commonParent: PsiElement) -> List<PsiElement>,
continuation: (elements: List<PsiElement>, targetSibling: PsiElement) -> Unit
) {
fun showErrorHintByKey(key: String) {
showErrorHint(file.getProject(), editor, JetRefactoringBundle.message(key), operationName)
}
fun onSelectionComplete(parent: PsiElement, elements: List<PsiElement>, targetContainer: PsiElement) {
if (parent == targetContainer) {
continuation(elements, elements.first())
return
}
val outermostParent = parent.getOutermostParentContainedIn(targetContainer)
if (outermostParent == null) {
showErrorHintByKey("cannot.refactor.no.container")
return
}
continuation(elements, outermostParent)
}
fun selectTargetContainer(elements: List<PsiElement>) {
val parent = PsiTreeUtil.findCommonParent(elements)
?: throw AssertionError("Should have at least one parent: ${elements.joinToString("\n")}")
val containers = getContainers(elements, parent)
if (containers.isEmpty()) {
showErrorHintByKey("cannot.refactor.no.container")
return
}
chooseContainerElementIfNecessary(
containers,
editor,
"Select target code block",
true,
{ it },
{ onSelectionComplete(parent, elements, it) }
)
}
fun selectMultipleExpressions() {
val startOffset = editor.getSelectionModel().getSelectionStart()
val endOffset = editor.getSelectionModel().getSelectionEnd()
val elements = CodeInsightUtils.findStatements(file, startOffset, endOffset)
if (elements.isEmpty()) {
showErrorHintByKey("cannot.refactor.no.expression")
return
}
selectTargetContainer(elements.toList())
}
fun selectSingleExpression() {
JetRefactoringUtil.selectExpression(editor, file, false) { expr ->
if (expr != null) {
selectTargetContainer(listOf(expr))
}
else {
if (!editor.getSelectionModel().hasSelection()) {
editor.getSelectionModel().selectLineAtCaret()
}
selectMultipleExpressions()
}
}
}
editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE)
selectSingleExpression()
}
@@ -21,7 +21,6 @@ import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.ExtractKotlinFunctionHandler
import java.io.File
import org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.selectElements
import org.jetbrains.kotlin.psi.JetTreeVisitorVoid
import com.intellij.psi.PsiComment
import com.intellij.refactoring.BaseRefactoringProcessor.ConflictsInTestsException
@@ -106,12 +105,11 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe
val renderer = DescriptorRenderer.DEBUG_TEXT
val editor = fixture.getEditor()
selectElements(editor, file) {(elements, previousSibling) ->
ExtractKotlinFunctionHandler(
helper = object : ExtractKotlinFunctionHandlerHelper() {
override fun adjustExtractionData(data: ExtractionData): ExtractionData {
return data.copy(options = extractionOptions)
}
val handler = ExtractKotlinFunctionHandler(
helper = object : ExtractKotlinFunctionHandlerHelper() {
override fun adjustExtractionData(data: ExtractionData): ExtractionData {
return data.copy(options = extractionOptions)
}
override fun adjustGeneratorOptions(options: ExtractionGeneratorOptions): ExtractionGeneratorOptions {
return options.copy(extractAsProperty = extractAsProperty)
@@ -124,13 +122,15 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe
it.getParameterTypeCandidates(extractionOptions.allowSpecialClassNames).map { renderer.renderType(it) }.joinToString(", ", "[", "]")
}.joinToString()
assertEquals(expectedDescriptors, actualDescriptors, "Expected descriptors mismatch.")
assertEquals(expectedTypes, actualTypes, "Expected types mismatch.")
assertEquals(expectedDescriptors, actualDescriptors, "Expected descriptors mismatch.")
assertEquals(expectedTypes, actualTypes, "Expected types mismatch.")
return if (descriptor.name == "") descriptor.copy(name = "__dummyTestFun__") else descriptor
}
return if (descriptor.name == "") descriptor.copy(name = "__dummyTestFun__") else descriptor
}
).doInvoke(editor, file, elements, explicitPreviousSibling ?: previousSibling)
}
)
handler.selectElements(editor, file) {(elements, previousSibling) ->
handler.doInvoke(editor, file, elements, explicitPreviousSibling ?: previousSibling)
}
}
}