diff --git a/annotations/com/intellij/codeInsight/unwrap/annotations.xml b/annotations/com/intellij/codeInsight/unwrap/annotations.xml
new file mode 100644
index 00000000000..d1c4ac95a8d
--- /dev/null
+++ b/annotations/com/intellij/codeInsight/unwrap/annotations.xml
@@ -0,0 +1,20 @@
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
\ No newline at end of file
diff --git a/annotations/com/intellij/ide/util/annotations.xml b/annotations/com/intellij/ide/util/annotations.xml
index ff27947d8a8..1f6acdd9f8e 100644
--- a/annotations/com/intellij/ide/util/annotations.xml
+++ b/annotations/com/intellij/ide/util/annotations.xml
@@ -5,4 +5,7 @@
-
+ -
+
+
\ No newline at end of file
diff --git a/annotations/com/intellij/openapi/editor/colors/annotations.xml b/annotations/com/intellij/openapi/editor/colors/annotations.xml
new file mode 100644
index 00000000000..bb3c07a1673
--- /dev/null
+++ b/annotations/com/intellij/openapi/editor/colors/annotations.xml
@@ -0,0 +1,5 @@
+
+ -
+
+
+
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/jet/plugin/JetIconProvider.java b/idea/src/org/jetbrains/jet/plugin/JetIconProvider.java
index acffc7a468d..c0ef085397d 100644
--- a/idea/src/org/jetbrains/jet/plugin/JetIconProvider.java
+++ b/idea/src/org/jetbrains/jet/plugin/JetIconProvider.java
@@ -123,6 +123,9 @@ public class JetIconProvider extends IconProvider {
return JetIcons.FUNCTION;
}
}
+
+ if (psiElement instanceof JetFunctionLiteral) return JetIcons.LAMBDA;
+
if (psiElement instanceof JetClass) {
JetClass jetClass = (JetClass) psiElement;
if (jetClass.isTrait()) {
diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java
index f089e29246e..0345cdbc5b3 100644
--- a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java
+++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java
@@ -57,6 +57,7 @@ import org.jetbrains.jet.plugin.JetBundle;
import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils;
import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
+import org.jetbrains.jet.plugin.util.UtilPackage;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import javax.swing.*;
@@ -509,11 +510,7 @@ public class JetRefactoringUtil {
}
public static String getExpressionShortText(@NotNull JetElement element) { //todo: write appropriate implementation
- String expressionText = element.getText();
- if (expressionText.length() > 20) {
- expressionText = expressionText.substring(0, 17) + "...";
- }
- return expressionText;
+ return UtilPackage.collapseSpaces(StringUtil.shortenTextWithEllipsis(element.getText(), 53, 0));
}
@Nullable
diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractKotlinFunctionHandler.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractKotlinFunctionHandler.kt
index 7113ba2184f..c5c42d6fa7b 100644
--- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractKotlinFunctionHandler.kt
+++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractKotlinFunctionHandler.kt
@@ -32,8 +32,6 @@ import org.jetbrains.jet.lang.psi.JetFile
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.jet.lang.psi.JetElement
import org.jetbrains.jet.plugin.refactoring.getAllExtractionContainers
-import com.intellij.refactoring.IntroduceTargetChooser
-import com.intellij.openapi.util.Pass
import com.intellij.openapi.application.ApplicationManager
import org.jetbrains.jet.lang.psi.psiUtil.getOutermostParentContainedIn
import org.jetbrains.jet.plugin.refactoring.checkConflictsInteractively
@@ -56,6 +54,17 @@ import org.jetbrains.jet.lang.psi.JetProperty
import org.jetbrains.jet.lang.psi.JetParameterList
import org.jetbrains.jet.lang.psi.JetClassInitializer
import org.jetbrains.jet.lang.psi.JetFunctionLiteral
+import com.intellij.ide.util.PsiElementListCellRenderer
+import com.intellij.openapi.util.text.StringUtil
+import javax.swing.Icon
+import org.jetbrains.jet.plugin.refactoring.getPsiElementPopup
+import com.intellij.psi.PsiNamedElement
+import org.jetbrains.jet.plugin.util.collapseSpaces
+import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
+import org.jetbrains.jet.lang.resolve.BindingContext
+import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
+import org.jetbrains.jet.renderer.DescriptorRenderer
+import org.jetbrains.jet.lang.psi.JetPropertyAccessor
import org.jetbrains.jet.lang.psi.JetClassOrObject
public class ExtractKotlinFunctionHandler(public val allContainersEnabled: Boolean = false) : RefactoringActionHandler {
@@ -222,33 +231,61 @@ fun selectElements(
return
}
- IntroduceTargetChooser.showChooser(
+ getPsiElementPopup(
editor,
- containers,
- object: Pass() {
- override fun pass(targetContainer: JetElement?) {
- if (targetContainer == null) {
- noContainerError()
- return
+ containers.copyToArray(),
+ object: PsiElementListCellRenderer() {
+ private fun JetElement.renderName(): String? {
+ if (this is JetPropertyAccessor) {
+ return (getParent() as JetProperty).renderName() + if (isGetter()) ".get" else ".set"
}
+ return (this as? PsiNamedElement)?.getName() ?: ""
+ }
- onSelectionComplete(parent, elements, targetContainer)
+ private fun JetElement.renderDeclaration(): String? {
+ val name = renderName()
+ val descriptor = AnalyzerFacadeWithCache.getContextForElement(this)[BindingContext.DECLARATION_TO_DESCRIPTOR, this]
+ val params = (descriptor as? FunctionDescriptor)?.let { descriptor ->
+ descriptor.getValueParameters()
+ .map { DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(it.getType()) }
+ .joinToString(", ", "(", ")")
+ } ?: ""
+ return "$name$params"
}
+
+ private fun JetElement.renderText(): String {
+ return StringUtil.shortenTextWithEllipsis(getText()!!.collapseSpaces(), 53, 0)
+ }
+
+ private fun JetElement.getRepresentativeElement(): JetElement {
+ return when (this) {
+ is JetBlockExpression -> (getParent() as? JetDeclarationWithBody) ?: this
+ is JetClassBody -> getParent() as JetClassOrObject
+ else -> this
+ }
+ }
+
+ override fun getElementText(element: JetElement): String? {
+ val representativeElement = element.getRepresentativeElement()
+ return when (representativeElement) {
+ is JetFile, is JetDeclarationWithBody, is JetClassOrObject -> representativeElement.renderDeclaration()
+ else -> representativeElement.renderText()
+ }
+ }
+
+ override fun getContainerText(element: JetElement?, name: String?): String? = null
+
+ override fun getIconFlags(): Int = 0
+
+ override fun getIcon(element: PsiElement?): Icon? =
+ super.getIcon((element as? JetElement)?.getRepresentativeElement())
},
+ "Select target code block",
{
- when (it) {
- is JetFile -> "File: ${it.getName()}"
- is JetBlockExpression -> {
- (it.getParent() as? JetDeclarationWithBody)?.getText() ?: "...${it.getStatements().first?.getText()}"
- }
- is JetClassBody -> {
- (it.getParent() as? JetClassOrObject)?.getText()
- }
- else -> it?.getText()
- }
- },
- "Select target code block"
- )
+ onSelectionComplete(parent, elements, it)
+ true
+ }
+ ).showInBestPositionFor(editor)
}
fun selectMultipleExpressions() {
diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/jetRefactoringUtil.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/jetRefactoringUtil.kt
index cf6139fa1ec..fad09f9baaf 100644
--- a/idea/src/org/jetbrains/jet/plugin/refactoring/jetRefactoringUtil.kt
+++ b/idea/src/org/jetbrains/jet/plugin/refactoring/jetRefactoringUtil.kt
@@ -46,7 +46,22 @@ import com.intellij.refactoring.ui.ConflictsDialog
import com.intellij.util.containers.MultiMap
import com.intellij.openapi.command.CommandProcessor
import org.jetbrains.jet.lang.psi.codeFragmentUtil.skipVisibilityCheck
-import com.intellij.openapi.ui.DialogWrapper
+import com.intellij.ide.util.PsiElementListCellRenderer
+import com.intellij.openapi.ui.popup.JBPopup
+import com.intellij.openapi.ui.popup.PopupChooserBuilder
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.util.TextRange
+import com.intellij.codeInsight.unwrap.RangeSplitter
+import com.intellij.codeInsight.unwrap.UnwrapHandler
+import com.intellij.openapi.editor.markup.TextAttributes
+import com.intellij.openapi.editor.markup.HighlighterTargetArea
+import com.intellij.openapi.editor.markup.RangeHighlighter
+import java.util.Collections
+import com.intellij.openapi.editor.colors.EditorColors
+import com.intellij.openapi.editor.colors.EditorColorsManager
+import com.intellij.ui.components.JBList
+import com.intellij.openapi.ui.popup.JBPopupAdapter
+import com.intellij.openapi.ui.popup.LightweightWindowEvent
/**
* Replace [[JetSimpleNameExpression]] (and its enclosing qualifier) with qualified element given by FqName
@@ -165,3 +180,73 @@ public fun Project.executeWriteCommand(name: String, command: () -> Unit) {
this, { ApplicationManager.getApplication()!!.runWriteAction(command) }, name, null
)
}
+
+public fun getPsiElementPopup(
+ editor: Editor,
+ elements: Array,
+ renderer: PsiElementListCellRenderer,
+ title: String? = null,
+ processor: (T) -> Boolean): JBPopup {
+ val highlighter = SelectionAwareScopeHighlighter(editor)
+
+ val list = JBList(elements.toList())
+ list.setCellRenderer(renderer)
+ list.addListSelectionListener { e ->
+ highlighter.dropHighlight()
+ val index = list.getSelectedIndex()
+ if (index >= 0) {
+ highlighter.highlight(list.getModel()!!.getElementAt(index) as PsiElement)
+ }
+ }
+
+ return with(PopupChooserBuilder(list)) {
+ title?.let { setTitle(it) }
+ renderer.installSpeedSearch(this, true)
+ setItemChoosenCallback {
+ for (element in list.getSelectedValues()) {
+ element.let {
+ [suppress("UNCHECKED_CAST")]
+ processor(it as T)
+ }
+ }
+ }
+ addListener(object: JBPopupAdapter() {
+ override fun onClosed(event: LightweightWindowEvent?) {
+ highlighter.dropHighlight();
+ }
+ })
+
+ createPopup()
+ }
+}
+
+public class SelectionAwareScopeHighlighter(val editor: Editor) {
+ private val highlighters = ArrayList()
+
+ private fun addHighlighter(r: TextRange, attr: TextAttributes) {
+ highlighters.add(
+ editor.getMarkupModel().addRangeHighlighter(
+ r.getStartOffset(),
+ r.getEndOffset(),
+ UnwrapHandler.HIGHLIGHTER_LEVEL,
+ attr,
+ HighlighterTargetArea.EXACT_RANGE
+ )
+ )
+ }
+
+ public fun highlight(wholeAffected: PsiElement) {
+ dropHighlight()
+
+ val attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES)!!
+ val selectedRange = with(editor.getSelectionModel()) { TextRange(getSelectionStart(), getSelectionEnd()) }
+ for (r in RangeSplitter.split(wholeAffected.getTextRange()!!, Collections.singletonList(selectedRange))) {
+ addHighlighter(r, attributes)
+ }
+ }
+
+ public fun dropHighlight() {
+ highlighters.forEach { it.dispose() }
+ highlighters.clear()
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/jet/plugin/util/stringUtil.kt b/idea/src/org/jetbrains/jet/plugin/util/stringUtil.kt
new file mode 100644
index 00000000000..ed0121ad110
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/util/stringUtil.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010-2014 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.jet.plugin.util
+
+fun String.collapseSpaces(): String {
+ val builder = StringBuilder()
+ var haveSpaces = false
+ for (c in this) {
+ if (c.isWhitespace()) {
+ haveSpaces = true
+ }
+ else {
+ if (haveSpaces) {
+ builder.append(" ")
+ haveSpaces = false
+ }
+ builder.append(c)
+ }
+ }
+ return builder.toString()
+}
\ No newline at end of file