[FIR IDE] Move IconProvider in fir independed module

This commit is contained in:
Igor Yakovlev
2020-08-28 18:03:11 +03:00
parent e30f09d513
commit 75347d06b9
15 changed files with 283 additions and 161 deletions
@@ -5,148 +5,9 @@
package org.jetbrains.kotlin.idea
import com.intellij.ide.IconProvider
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.IndexNotReadyException
import com.intellij.openapi.util.Iconable
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiElement
import com.intellij.ui.RowIcon
import com.intellij.util.PlatformIcons
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.idea.KotlinIcons.ACTUAL
import org.jetbrains.kotlin.idea.KotlinIcons.EXPECT
import org.jetbrains.kotlin.idea.caches.lightClasses.KtLightClassForDecompiledDeclaration
import org.jetbrains.kotlin.idea.util.hasMatchingExpected
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isAbstract
import javax.swing.Icon
import org.jetbrains.kotlin.psi.KtDeclaration
class KotlinIconProvider : IconProvider(), DumbAware {
override fun getIcon(psiElement: PsiElement, flags: Int): Icon? {
if (psiElement is KtFile) {
if (psiElement.isScript()) {
return when {
psiElement.name.endsWith(".gradle.kts") -> KotlinIcons.GRADLE_SCRIPT
else -> KotlinIcons.SCRIPT
}
}
val mainClass = getSingleClass(psiElement)
return if (mainClass != null) getIcon(mainClass, flags) else KotlinIcons.FILE
}
val result = psiElement.getBaseIcon()
if (flags and Iconable.ICON_FLAG_VISIBILITY > 0 && result != null && (psiElement is KtModifierListOwner && psiElement !is KtClassInitializer)) {
val list = psiElement.modifierList
val visibilityIcon = getVisibilityIcon(list)
val withExpectedActual: Icon = try {
result.addExpectActualMarker(psiElement)
} catch (indexNotReady: IndexNotReadyException) {
result
}
return createRowIcon(withExpectedActual, visibilityIcon)
}
return result
}
companion object {
var INSTANCE = KotlinIconProvider()
fun isSingleClassFile(file: KtFile) = getSingleClass(file) != null
fun getSingleClass(file: KtFile): KtClassOrObject? {
val mainClass = getMainClass(file)
return if (mainClass != null && file.declarations.size == 1) mainClass else null
}
fun getMainClass(file: KtFile): KtClassOrObject? {
val classes = file.declarations.filterIsInstance<KtClassOrObject>()
if (classes.size == 1 && StringUtil.getPackageName(file.name) == classes[0].name) {
return classes[0]
}
return null
}
private fun createRowIcon(baseIcon: Icon, visibilityIcon: Icon): RowIcon {
val rowIcon = RowIcon(2)
rowIcon.setIcon(baseIcon, 0)
rowIcon.setIcon(visibilityIcon, 1)
return rowIcon
}
fun getVisibilityIcon(list: KtModifierList?): Icon {
if (list != null) {
if (list.hasModifier(KtTokens.PRIVATE_KEYWORD)) {
return PlatformIcons.PRIVATE_ICON
}
if (list.hasModifier(KtTokens.PROTECTED_KEYWORD)) {
return PlatformIcons.PROTECTED_ICON
}
if (list.hasModifier(KtTokens.INTERNAL_KEYWORD)) {
return PlatformIcons.PACKAGE_LOCAL_ICON
}
}
return PlatformIcons.PUBLIC_ICON
}
fun PsiElement.getBaseIcon(): Icon? = when (this) {
is KtPackageDirective -> PlatformIcons.PACKAGE_ICON
is KtLightClassForFacade -> KotlinIcons.FILE
is KtLightClassForDecompiledDeclaration -> {
val origin = kotlinOrigin
//TODO (light classes for decompiled files): correct presentation
if (origin != null) origin.getBaseIcon() else KotlinIcons.CLASS
}
is KtLightClassForSourceDeclaration -> navigationElement.getBaseIcon()
is KtNamedFunction -> when {
receiverTypeReference != null ->
if (KtPsiUtil.isAbstract(this)) KotlinIcons.ABSTRACT_EXTENSION_FUNCTION else KotlinIcons.EXTENSION_FUNCTION
getStrictParentOfType<KtNamedDeclaration>() is KtClass ->
if (KtPsiUtil.isAbstract(this)) PlatformIcons.ABSTRACT_METHOD_ICON else PlatformIcons.METHOD_ICON
else ->
KotlinIcons.FUNCTION
}
is KtConstructor<*> -> PlatformIcons.METHOD_ICON
is KtFunctionLiteral -> KotlinIcons.LAMBDA
is KtClass -> when {
isInterface() -> KotlinIcons.INTERFACE
isEnum() -> KotlinIcons.ENUM
isAnnotation() -> KotlinIcons.ANNOTATION
this is KtEnumEntry && getPrimaryConstructorParameterList() == null -> KotlinIcons.ENUM
else -> if (isAbstract()) KotlinIcons.ABSTRACT_CLASS else KotlinIcons.CLASS
}
is KtObjectDeclaration -> KotlinIcons.OBJECT
is KtParameter -> {
if (KtPsiUtil.getClassIfParameterIsProperty(this) != null) {
if (isMutable) KotlinIcons.FIELD_VAR else KotlinIcons.FIELD_VAL
} else
KotlinIcons.PARAMETER
}
is KtProperty -> if (isVar) KotlinIcons.FIELD_VAR else KotlinIcons.FIELD_VAL
is KtClassInitializer -> KotlinIcons.CLASS_INITIALIZER
is KtTypeAlias -> KotlinIcons.TYPE_ALIAS
else -> unwrapped?.takeIf { it != this }?.getBaseIcon()
}
}
}
private fun Icon.addExpectActualMarker(element: PsiElement): Icon {
val declaration = (element as? KtNamedDeclaration) ?: return this
val additionalIcon = when {
declaration.isExpectDeclaration() -> EXPECT
declaration.hasMatchingExpected() -> ACTUAL
else -> return this
}
return RowIcon(2).apply {
setIcon(this@addExpectActualMarker, 0)
setIcon(additionalIcon, 1)
}
}
class KotlinIconProvider : KotlinIconProviderBase() {
override fun KtDeclaration.isMatchingExpected() = hasMatchingExpected()
}
@@ -24,7 +24,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.KotlinIconProvider;
import org.jetbrains.kotlin.idea.KotlinIconProviderBase;
import org.jetbrains.kotlin.psi.KtFile;
public class KotlinStructureViewFactory implements PsiStructureViewFactory {
@@ -44,7 +44,7 @@ public class KotlinStructureViewFactory implements PsiStructureViewFactory {
@Override
public boolean isRootNodeShown() {
return !KotlinIconProvider.Companion.isSingleClassFile(file);
return !KotlinIconProviderBase.Companion.isSingleClassFile(file);
}
};
}