[kotlin] k2: main.kts improvements

GitOrigin-RevId: fb9a42861b7e0862aa744d19d647a5d53da51940
This commit is contained in:
Vlad Koshkin
2024-07-29 16:47:45 +02:00
committed by intellij-monorepo-bot
parent 24e3315d5e
commit 71c20d85f7
9 changed files with 118 additions and 21 deletions

View File

@@ -22,15 +22,7 @@ import org.jetbrains.kotlin.analysis.api.impl.base.projectStructure.KaBuiltinsMo
import org.jetbrains.kotlin.analysis.api.platform.modification.KotlinModificationTrackerFactory
import org.jetbrains.kotlin.analysis.api.platform.projectStructure.KotlinProjectStructureProvider
import org.jetbrains.kotlin.analysis.api.platform.projectStructure.KotlinProjectStructureProviderBase
import org.jetbrains.kotlin.analysis.api.projectStructure.KaBuiltinsModule
import org.jetbrains.kotlin.analysis.api.projectStructure.KaLibraryModule
import org.jetbrains.kotlin.analysis.api.projectStructure.KaLibrarySourceModule
import org.jetbrains.kotlin.analysis.api.projectStructure.KaModule
import org.jetbrains.kotlin.analysis.api.projectStructure.KaNotUnderContentRootModule
import org.jetbrains.kotlin.analysis.api.projectStructure.KaScriptDependencyModule
import org.jetbrains.kotlin.analysis.api.projectStructure.KaScriptModule
import org.jetbrains.kotlin.analysis.api.projectStructure.KaSourceModule
import org.jetbrains.kotlin.analysis.api.projectStructure.danglingFileResolutionMode
import org.jetbrains.kotlin.analysis.api.projectStructure.*
import org.jetbrains.kotlin.analysis.decompiler.psi.BuiltinsVirtualFileProvider
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.idea.base.facet.platform.platform
@@ -167,7 +159,7 @@ internal class ProjectStructureProviderIdeImpl(private val project: Project) : K
val config = ModuleInfoProvider.Configuration(
createSourceLibraryInfoForLibraryBinaries = false,
preferModulesFromExtensions = isScriptOrItsDependency(contextualModule, virtualFile) &&
(!RootKindFilter.projectSources.matches(psiElement) || this.isInSpecialSrcDir(psiElement)),
(!RootKindFilter.projectSources.matches(psiElement) || isInSpecialSrcDir(psiElement)),
contextualModuleInfo = contextualModule?.ideaModuleInfo,
)

View File

@@ -16,5 +16,9 @@ notification.action.text.apply.context=Apply context
notification.action.text.enable.auto.reload=Enable auto-reload
scripting.support.availability.name=Kotlin scripting
action.LoadMainKtsConfiguration.text=Refresh Script
action.LoadMainKtsConfiguration.text=Load Script Dependencies
action.LoadMainKtsConfiguration.description=Load script dependencies and re-highlight
progress.title.loading.script.dependencies=Loading script dependencies\u2026
notification.main.kts.unable.execute=Unable to execute current script: lack of permissions
notification.main.kts.make.executable=Make script executable

View File

@@ -50,13 +50,12 @@ class MainKtsScriptDependenciesSource(override val project: Project) : ScriptDep
}
override suspend fun updateModules(dependencies: ScriptDependenciesData, storage: MutableEntityStorage?) {
val workspaceModel = project.workspaceModel
val storageSnapshot = workspaceModel.currentSnapshot
val storageSnapshot = project.workspaceModel.currentSnapshot
val tempStorage = MutableEntityStorage.from(storageSnapshot)
creteScriptModules(project, dependencies, tempStorage)
workspaceModel.update("Updating MainKts Kotlin Scripts modules") {
project.workspaceModel.update("Updating MainKts Kotlin Scripts modules") {
it.applyChangesFrom(tempStorage)
}
}

View File

@@ -0,0 +1,44 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.script.k2
import com.intellij.openapi.fileEditor.FileEditor
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiManager
import com.intellij.ui.EditorNotificationPanel
import com.intellij.ui.EditorNotificationProvider
import com.intellij.ui.EditorNotifications
import org.jetbrains.kotlin.idea.base.scripting.KotlinBaseScriptingBundle
import org.jetbrains.kotlin.idea.util.isKotlinFileType
import org.jetbrains.kotlin.psi.KtFile
import java.io.File
import java.util.function.Function
import javax.swing.JComponent
class MainKtsScriptNotificationProvider : EditorNotificationProvider {
override fun collectNotificationData(project: Project, file: VirtualFile): Function<in FileEditor, out JComponent?>? {
if (!isMainKtsScript(file) || !file.isKotlinFileType()) {
return null
}
return Function { fileEditor ->
when {
shouldBeExecutable(file, project) ->
EditorNotificationPanel(fileEditor, EditorNotificationPanel.Status.Info).apply {
text(KotlinBaseScriptingBundle.message("notification.main.kts.unable.execute"))
createActionLabel(KotlinBaseScriptingBundle.message("notification.main.kts.make.executable")) {
File(file.path).setExecutable(true)
EditorNotifications.getInstance(project).updateNotifications(file)
}
}
else -> null
}
}
}
private fun shouldBeExecutable(file: VirtualFile, project: Project): Boolean {
val ktFile = PsiManager.getInstance(project).findFile(file) as? KtFile ?: return false
return ktFile.hasShebangComment() && !File(file.path).canExecute()
}
}

View File

@@ -0,0 +1,29 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.script.k2
import com.intellij.openapi.module.Module
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
import org.jetbrains.kotlin.idea.base.projectStructure.NewKotlinFileHook
import org.jetbrains.kotlin.idea.base.scripting.KotlinBaseScriptingBundle
import org.jetbrains.kotlin.idea.core.script.k2.BaseScriptModel
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class NewMainKtsFileHook : NewKotlinFileHook() {
override fun postProcess(createdElement: KtFile, module: Module) {
val virtualFile = createdElement.virtualFile
val ktFile = createdElement.safeAs<KtFile>() ?: return
if (!isMainKtsScript(virtualFile) || !ktFile.isScript()) return
val project = ktFile.project
runWithModalProgressBlocking(
project,
KotlinBaseScriptingBundle.message("progress.title.loading.script.dependencies")
) {
MainKtsScriptDependenciesSource.getInstance(project)?.updateDependenciesAndCreateModules(
listOf(BaseScriptModel(virtualFile))
)
}
}
}

View File

@@ -1,5 +1,5 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.script
package org.jetbrains.kotlin.idea.script.k2
import com.intellij.diff.util.DiffUtil
import com.intellij.openapi.actionSystem.ActionUpdateThread
@@ -11,13 +11,15 @@ import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
import com.intellij.testFramework.LightVirtualFileBase
import com.intellij.ui.EditorNotifications
import org.jetbrains.kotlin.idea.base.scripting.KotlinBaseScriptingBundle
import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesModificationTracker
import org.jetbrains.kotlin.idea.core.script.k2.BaseScriptModel
import org.jetbrains.kotlin.idea.script.k2.MainKtsScriptDependenciesSource
import org.jetbrains.kotlin.idea.util.isKotlinFileType
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionProvider
import java.util.concurrent.ConcurrentHashMap
internal class RefreshMainKtsScriptAction : AnAction() {
internal class ReloadDependenciesMainKtsScriptAction : AnAction() {
private val lastModifiedPerScript = ConcurrentHashMap<VirtualFile, Long>()
@@ -28,11 +30,15 @@ internal class RefreshMainKtsScriptAction : AnAction() {
runWithModalProgressBlocking(
project,
"Compiling script..."
KotlinBaseScriptingBundle.message("progress.title.loading.script.dependencies")
) {
MainKtsScriptDependenciesSource.getInstance(project)?.updateDependenciesAndCreateModules(
listOf(BaseScriptModel(file))
)
ScriptDependenciesModificationTracker.getInstance(project).incModificationCount()
lastModifiedPerScript[file] = file.modificationStamp
EditorNotifications.getInstance(project).updateNotifications(file)
}
}
@@ -66,5 +72,3 @@ private fun getKotlinScriptFile(editor: Editor): VirtualFile? = FileDocumentMana
&& it.isKotlinFileType()
&& isMainKtsScript(it)
}
private fun isMainKtsScript(virtualFile: VirtualFile) = virtualFile.name.endsWith(".main.kts")

View File

@@ -0,0 +1,22 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.script.k2
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.SyntaxTraverser
import com.intellij.util.containers.TreeTraversal
import org.jetbrains.kotlin.lexer.KtTokens.SHEBANG_COMMENT
fun isMainKtsScript(virtualFile: VirtualFile) = virtualFile.name.endsWith(".main.kts")
fun PsiFile.hasShebangComment(): Boolean =
SyntaxTraverser.psiTraverser(/* root = */ this)
.withTraversal(TreeTraversal.LEAVES_DFS)
.traverse()
.filterIsInstance<PsiComment>()
.any { element: PsiElement -> element.isShebangComment() }
private fun PsiElement.isShebangComment(): Boolean =
this is PsiComment && tokenType === SHEBANG_COMMENT

View File

@@ -63,6 +63,8 @@
</extensionPoints>
<extensions defaultExtensionNs="com.intellij">
<editorNotificationProvider implementation="org.jetbrains.kotlin.idea.script.k2.MainKtsScriptNotificationProvider"/>
<registryKey defaultValue="false"
key="kotlin.k2.scripting.show.modules"
description="Enable displaying Kotlin Script modules in 'Project Structure' | 'Modules' view "/>
@@ -105,6 +107,7 @@
</extensions>
<extensions defaultExtensionNs="org.jetbrains.kotlin">
<newFileHook implementation="org.jetbrains.kotlin.idea.script.k2.NewMainKtsFileHook"/>
<ktModuleFactory implementation="org.jetbrains.kotlin.idea.base.scripting.projectStructure.ScriptingKaModuleFactory"/>
<idea.base.platforms.targetPlatformDetector implementation="org.jetbrains.kotlin.idea.base.scripting.ScriptingTargetPlatformDetector"/>
@@ -118,7 +121,7 @@
<actions resource-bundle="messages.KotlinBaseScriptingBundle">
<action id="LoadMainKtsConfiguration"
class="org.jetbrains.kotlin.idea.script.RefreshMainKtsScriptAction"
class="org.jetbrains.kotlin.idea.script.k2.ReloadDependenciesMainKtsScriptAction"
icon="org.jetbrains.kotlin.idea.KotlinIcons.LOAD_SCRIPT_CONFIGURATION">
<add-to-group group-id="EditorContextBarMenu"/>
</action>