[kotlin] Improve scripts navigation experience

#KTIJ-24328 Fixed

GitOrigin-RevId: d9215f81985a301a8dd7273e7e05f0af5af86acf
This commit is contained in:
Vladimir Dolzhenko
2023-01-18 23:33:25 +00:00
committed by intellij-monorepo-bot
parent 181d1cdcc0
commit 13871f57c3
13 changed files with 113 additions and 43 deletions
@@ -25,11 +25,14 @@ open class KotlinStructureViewModel(ktFile: KtFile, editor: Editor?, rootElement
withSorters(KotlinVisibilitySorter, Sorter.ALPHA_SORTER)
}
override fun isSuitable(element: PsiElement?): Boolean = element is KtDeclaration &&
override fun isSuitable(element: PsiElement?): Boolean =
element is KtDeclaration &&
element !is KtPropertyAccessor &&
element !is KtFunctionLiteral &&
!(element is KtProperty && element.parent !is KtFile && element.containingClassOrObject !is KtNamedDeclaration) &&
!(element is KtFunction && element.parent !is KtFile && element.containingClassOrObject !is KtNamedDeclaration)
!((element is KtProperty || element is KtFunction) && !element.topLevelDeclaration && element.containingClassOrObject !is KtNamedDeclaration)
private val KtDeclaration.topLevelDeclaration: Boolean
get() = parent is KtFile || parent is KtBlockExpression && parent.parent is KtScript
override fun getFilters() = FILTERS
@@ -3,20 +3,19 @@
package org.jetbrains.kotlin.idea.navigationToolbar
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNamedElement
import org.jetbrains.kotlin.idea.KotlinIconProvider
import org.jetbrains.kotlin.idea.projectView.KtDeclarationTreeNode.Companion.tryGetRepresentableText
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedFunction
class KotlinNavBarModelExtension : AbstractNavBarModelExtensionCompatBase() {
override fun getPresentableText(item: Any?): String? {
val fullText = (item as? KtDeclaration)?.let { tryGetRepresentableText(it) }
return when (item) {
is KtNamedFunction -> fullText?.substringBefore('(')
else -> fullText
override fun getPresentableText(item: Any?): String? =
when (item) {
is KtDeclaration -> tryGetRepresentableText(item, renderArguments = false)
is PsiNamedElement -> item.name
else -> null
}
}
override fun adjustElementImpl(psiElement: PsiElement?): PsiElement? {
if (psiElement is KtDeclaration) {
@@ -24,7 +23,6 @@ class KotlinNavBarModelExtension : AbstractNavBarModelExtensionCompatBase() {
}
val containingFile = psiElement?.containingFile as? KtFile ?: return psiElement
if (containingFile.isScript()) return psiElement
return KotlinIconProvider.getSingleClass(containingFile) ?: psiElement
}
}
@@ -36,7 +36,7 @@ internal class KtDeclarationTreeNode private constructor(
private fun String?.orErrorName() = if (!isNullOrBlank()) this else ERROR_NAME
@NlsSafe
fun tryGetRepresentableText(declaration: KtDeclaration): String {
fun tryGetRepresentableText(declaration: KtDeclaration, renderArguments: Boolean = true): String {
val settings = declaration.containingKtFile.kotlinCustomSettings
fun StringBuilder.appendColon() {
if (settings.SPACE_BEFORE_TYPE_COLON) append(" ")
@@ -58,21 +58,23 @@ internal class KtDeclarationTreeNode private constructor(
append('.')
}
append(name.orErrorName())
append("(")
val valueParameters = valueParameters
valueParameters.forEachIndexed { index, parameter ->
parameter.name?.let { parameterName ->
append(parameterName)
appendColon()
}
parameter.typeReference?.text?.let { typeReference ->
append(typeReference)
}
if (index != valueParameters.size - 1) {
append(", ")
if (renderArguments) {
append("(")
val valueParameters = valueParameters
valueParameters.forEachIndexed { index, parameter ->
parameter.name?.let { parameterName ->
append(parameterName)
appendColon()
}
parameter.typeReference?.text?.let { typeReference ->
append(typeReference)
}
if (index != valueParameters.size - 1) {
append(", ")
}
}
append(")")
}
append(")")
typeReference?.text?.let { returnTypeReference ->
appendColon()
@@ -14,10 +14,8 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.KotlinDescriptorIconProvider
import org.jetbrains.kotlin.idea.KotlinIdeaBundle
import org.jetbrains.kotlin.psi.KtAnonymousInitializer
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.idea.projectView.KtDeclarationTreeNode.Companion.tryGetRepresentableText
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.renderer.DescriptorRenderer.Companion.ONLY_NAMES_WITH_SHORT_TYPES
import org.jetbrains.kotlin.resolve.DescriptorUtils.getAllOverriddenDeclarations
import org.jetbrains.kotlin.resolve.OverridingUtil.filterOutOverridden
@@ -82,16 +80,9 @@ internal class KotlinStructureElementPresentation(
return ONLY_NAMES_WITH_SHORT_TYPES.render(descriptor)
}
val text = navigatablePsiElement.name
if (!text.isNullOrEmpty()) {
return text
}
navigatablePsiElement.name.takeUnless { it.isNullOrEmpty() }?.let { return it }
if (navigatablePsiElement is KtAnonymousInitializer) {
return KotlinIdeaBundle.message("class.initializer")
}
return null
return (navigatablePsiElement as? KtDeclaration)?.let { tryGetRepresentableText(it) }
}
private fun getElementLocationString(isInherited: Boolean, descriptor: DeclarationDescriptor?): String? {
@@ -66,7 +66,15 @@ class KotlinStructureViewElement(
override fun getChildrenBase(): Collection<StructureViewTreeElement> {
val children = when (val element = element) {
is KtFile -> element.declarations
is KtFile -> {
val declarations = element.declarations
// it is a bit faster that `element.isScript()`
if (declarations.size == 1 && declarations[0] is KtScript) {
declarations[0] as KtScript
} else {
element
}.declarations
}
is KtClass -> element.getStructureDeclarations()
is KtClassOrObject -> element.declarations
is KtFunction, is KtClassInitializer, is KtProperty -> element.collectLocalDeclarations()
@@ -23,6 +23,16 @@ public class KotlinNavBarTestGenerated extends AbstractKotlinNavBarTest {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("build1.gradle.kts")
public void testBuild1_gradle() throws Exception {
runTest("testData/navigationToolbar/build1.gradle.kts");
}
@TestMetadata("build2.gradle.kts")
public void testBuild2_gradle() throws Exception {
runTest("testData/navigationToolbar/build2.gradle.kts");
}
@TestMetadata("ClassProperty.kt")
public void testClassProperty() throws Exception {
runTest("testData/navigationToolbar/ClassProperty.kt");
@@ -13,7 +13,9 @@ import java.io.File
abstract class AbstractKotlinFileStructureTest : KotlinFileStructureTestBase() {
override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.getInstance()
override val fileExtension = "kt"
override val fileExtension: String
get() = fileName().substringAfter(".")
override val treeFileName: String get() = getFileName("after")
fun doTest(path: String) {
@@ -25,7 +27,7 @@ abstract class AbstractKotlinFileStructureTest : KotlinFileStructureTestBase() {
}
protected fun FileStructurePopup.setup() {
val fileText = FileUtil.loadFile(File(testDataPath, fileName()), true)
val fileText = FileUtil.loadFile(File(testDataDirectory, fileName()), true)
val withInherited = InTextDirectivesUtils.isDirectiveDefined(fileText, "WITH_INHERITED")
setTreeActionState(nodeProviderClass(), withInherited)
@@ -103,6 +103,11 @@ public class KotlinFileStructureTestGenerated extends AbstractKotlinFileStructur
runTest("testData/structureView/fileStructure/Render.kt");
}
@TestMetadata("Script.kts")
public void testScript() throws Exception {
runTest("testData/structureView/fileStructure/Script.kts");
}
@TestMetadata("SeveralClasses.kt")
public void testSeveralClasses() throws Exception {
runTest("testData/structureView/fileStructure/SeveralClasses.kt");
@@ -0,0 +1,14 @@
// NAV_BAR_ITEMS: src, build1.gradle.kts, repositories
plugins {
kotlin("jvm") version "1.7.10"
application
}
repositories {
mavenCentral()<caret>
}
dependencies {
implementation(kotlin("stdlib-jdk8"))
}
@@ -0,0 +1,18 @@
// NAV_BAR_ITEMS: src, build2.gradle.kts, someFun
plugins {
kotlin("jvm") version "1.7.10"
application
}
repositories {
mavenCentral()
}
dependencies {
implementation(kotlin("stdlib-jdk8"))
}
fun someFun() {
TODO()<caret>
}
@@ -0,0 +1,5 @@
-Script.kts
dependencies
foo(): Unit
plugins
repositories
@@ -0,0 +1,14 @@
plugins {
kotlin("jvm") version "1.7.10"
application
}
repositories {
mavenCentral()<caret>
}
dependencies {
implementation(kotlin("stdlib-jdk8"))
}
fun foo() {}
@@ -781,7 +781,7 @@ private fun assembleWorkspace(): TWorkspace = workspace {
}
testClass<AbstractKotlinFileStructureTest> {
model("structureView/fileStructure", pattern = KT_WITHOUT_DOTS)
model("structureView/fileStructure", pattern = KT_OR_KTS_WITHOUT_DOTS)
}
testClass<AbstractExpressionSelectionTest> {
@@ -993,7 +993,7 @@ private fun assembleWorkspace(): TWorkspace = workspace {
}
testClass<AbstractKotlinNavBarTest> {
model("navigationToolbar", isRecursive = false)
model("navigationToolbar", pattern = KT_OR_KTS, isRecursive = false)
}
}