Search Everywhere: Update renderer to reflect changes in IDEA

#KT-24812 Fixed
This commit is contained in:
Alexey Sedunov
2018-06-07 17:31:32 +03:00
parent 31d248c42d
commit 83745010ba
@@ -16,66 +16,165 @@
package org.jetbrains.kotlin.idea.goto
import com.intellij.ide.util.DefaultPsiElementCellRenderer
import com.intellij.ide.util.PlatformModuleRendererFactory
import com.intellij.ide.util.PsiElementListCellRenderer
import com.intellij.ide.util.gotoByName.GotoFileCellRenderer
import com.intellij.navigation.NavigationItem
import com.intellij.openapi.util.Iconable
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFileSystemItem
import com.intellij.psi.presentation.java.SymbolPresentationUtil
import com.intellij.ui.ColoredListCellRenderer
import com.intellij.ui.JBColor
import com.intellij.ui.SimpleTextAttributes
import com.intellij.util.ui.FilePathSplittingPolicy
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.renderer.ParameterNameRenderingPolicy
import java.awt.BorderLayout
import java.awt.Container
import java.io.File
import java.util.*
import javax.swing.DefaultListCellRenderer
import javax.swing.JList
class KotlinSearchEverywherePsiRenderer(private val list: JList<*>) : DefaultPsiElementCellRenderer() {
private val RENDERER = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.withOptions {
parameterNameRenderingPolicy = ParameterNameRenderingPolicy.NONE
modifiers = emptySet()
startFromName = false
// Mostly copied from com.intellij.ide.actions.SearchEverywherePsiRenderer
// TODO: Drop copied code when SearchEverywherePsiRenderer becomes public
internal class KotlinSearchEverywherePsiRenderer(private val myList: JList<*>) : PsiElementListCellRenderer<PsiElement>() {
companion object {
private val RENDERER = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.withOptions {
parameterNameRenderingPolicy = ParameterNameRenderingPolicy.NONE
modifiers = emptySet()
startFromName = false
}
}
override fun getElementText(element: PsiElement?): String {
if (element is KtNamedFunction) {
val descriptor = element.resolveToDescriptorIfAny()
if (descriptor != null) {
return buildString {
descriptor.extensionReceiverParameter?.let { append(RENDERER.renderType(it.type)).append('.') }
append(element.name)
descriptor.valueParameters.joinTo(this, prefix = "(", postfix = ")") { RENDERER.renderType(it.type) }
init {
setFocusBorderEnabled(false)
layout = object : BorderLayout() {
override fun layoutContainer(target: Container) {
super.layoutContainer(target)
val right = getLayoutComponent(BorderLayout.EAST)
val left = getLayoutComponent(BorderLayout.WEST)
//IDEA-140824
if (right != null && left != null && left.bounds.x + left.bounds.width > right.bounds.x) {
val bounds = right.bounds
val newX = left.bounds.x + left.bounds.width
right.setBounds(newX, bounds.y, bounds.width - (newX - bounds.x), bounds.height)
}
}
}
return super.getElementText(element)
}
// Mostly copied from SearchEverywherePsiRenderer
override fun getContainerText(element: PsiElement?, name: String?): String? {
var text = SymbolPresentationUtil.getSymbolContainerText(element) ?: return null
if (list.width == 0) return text
override fun getElementText(element: PsiElement?): String {
if (element !is KtNamedFunction) return ""
val descriptor = element.resolveToDescriptorIfAny() ?: return ""
return buildString {
descriptor.extensionReceiverParameter?.let { append(RENDERER.renderType(it.type)).append('.') }
append(element.name)
descriptor.valueParameters.joinTo(this, prefix = "(", postfix = ")") { RENDERER.renderType(it.type) }
}
}
override fun getContainerText(element: PsiElement, name: String): String? {
if (element is PsiFileSystemItem) {
val file = element.virtualFile
val parent = file?.parent
if (parent == null) {
if (file != null) { // use fallback from Switcher
val presentableUrl = file.presentableUrl
return FileUtil.getLocationRelativeToUserHome(presentableUrl)
}
return null
}
val relativePath = GotoFileCellRenderer.getRelativePath(parent, element.getProject()) ?: return "( " + File.separator + " )"
var width = myList.width
if (width == 0) width += 800
val path = FilePathSplittingPolicy.SPLIT_BY_SEPARATOR.getOptimalTextForComponent(
name,
File(relativePath),
this,
width - myRightComponentWidth - 16 - 10
)
return "($path)"
}
return getSymbolContainerText(name, element)
}
private fun getSymbolContainerText(name: String, element: PsiElement): String? {
var text = SymbolPresentationUtil.getSymbolContainerText(element)
if (myList.width == 0) return text
if (text == null) return null
if (text.startsWith("(") && text.endsWith(")")) {
text = text.substring(1, text.length - 1)
}
val inIndex = text.indexOf("in ")
if (inIndex >= 0) text = text.substring(inIndex + 3)
val fm = list.getFontMetrics(list.font)
val maxWidth = list.width - fm.stringWidth(name) - 16 - myRightComponentWidth - 20
val left = if (inIndex >= 0) "(in " else "("
val `in` = text.startsWith("in ")
if (`in`) text = text.substring(3)
val fm = myList.getFontMetrics(myList.font)
val maxWidth = myList.width - fm.stringWidth(name) - 16 - myRightComponentWidth - 20
val left = if (`in`) "(in " else "("
val right = ")"
if (fm.stringWidth(left + text + right) < maxWidth) return left + text + right
val parts = LinkedList(StringUtil.split(text, "."))
val separator = if (text.contains(File.separator)) File.separator else "."
val parts = LinkedList(StringUtil.split(text, separator))
var index: Int
while (parts.size > 1) {
index = parts.size / 2 - 1
parts.removeAt(index)
if (fm.stringWidth(StringUtil.join(parts, ".") + "...") < maxWidth) {
parts.add(index, if (index == 0) "..." else ".")
return left + StringUtil.join(parts, ".") + right
if (fm.stringWidth(StringUtil.join(parts, separator) + "...") < maxWidth) {
parts.add(index, "...")
return left + StringUtil.join(parts, separator) + right
}
}
return left + "..." + right
//todo
return "$left...$right"
}
}
override fun customizeNonPsiElementLeftRenderer(
renderer: ColoredListCellRenderer<*>?,
list: JList<*>?,
value: Any?,
index: Int,
selected: Boolean,
hasFocus: Boolean
): Boolean {
if (value !is NavigationItem) return false
val item = value as NavigationItem?
val attributes = getNavigationItemAttributes(item)
var nameAttributes: SimpleTextAttributes? = if (attributes != null) SimpleTextAttributes.fromTextAttributes(attributes) else null
val color = list!!.foreground
if (nameAttributes == null) nameAttributes = SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, color)
renderer!!.append(item!!.toString() + " ", nameAttributes)
val itemPresentation = item.presentation!!
renderer.icon = itemPresentation.getIcon(true)
val locationString = itemPresentation.locationString
if (!StringUtil.isEmpty(locationString)) {
renderer.append(locationString!!, SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, JBColor.GRAY))
}
return true
}
override fun getRightCellRenderer(value: Any): DefaultListCellRenderer? {
val rightRenderer = super.getRightCellRenderer(value)
return if (rightRenderer is PlatformModuleRendererFactory.PlatformModuleRenderer) {
// that renderer will display file path, but we're showing it ourselves - no need to show twice
null
} else rightRenderer
}
override fun getIconFlags() = Iconable.ICON_FLAG_READ_STATUS
}