Skip to content

Commit

Permalink
Fix RubyMine umbrella apps, revert the reverted kotlin code change (#…
Browse files Browse the repository at this point in the history
…3643)

RubyMine is currently a bit wonky for new projects.

This an interim fix until better support is added for custom languages.
  • Loading branch information
joshuataylor authored Aug 20, 2024
1 parent f925de6 commit b698fda
Show file tree
Hide file tree
Showing 29 changed files with 1,221 additions and 1,295 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
* [#3640](https://github.com/KronicDeth/intellij-elixir/pull/3640) - [@joshuataylor](https://github.com/joshuataylor)
* Bump intellij platform gradle to 2.0.1 and IdeaVIM to 2.16.0

* [#3643](https://github.com/KronicDeth/intellij-elixir/pull/3643) - [@joshuataylor](https://github.com/joshuataylor)
* Fix RubyMine freezing for umbrella projects but showing the new project wizard as a temporary workaround.

## v19.0.0

### Breaking changes
Expand Down
17 changes: 17 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
import org.jetbrains.intellij.platform.gradle.TestFrameworkType
import org.jetbrains.intellij.platform.gradle.tasks.RunIdeTask

plugins {
id "org.jetbrains.intellij.platform" version "2.0.1"
Expand Down Expand Up @@ -125,6 +126,22 @@ intellijPlatform {
}
apply plugin: "kotlin"

tasks.withType(RunIdeTask) {
// Set JVM arguments
jvmArguments.addAll(["-Didea.debug.mode=true", "-Didea.is.internal=true", "-Dlog4j2.debug=true", "-Dlogger.org=TRACE", "-XX:+AllowEnhancedClassRedefinition"])

// Set system properties to debug log
systemProperty "idea.log.debug.categories", "org.elixir_lang"

// Set the maximum heap size
maxHeapSize = "7g"

// Optionally set the working directory if specified in the project properties
if (project.hasProperty("runIdeWorkingDirectory") && !project.property("runIdeWorkingDirectory").isEmpty()) {
workingDir = file(project.property("runIdeWorkingDirectory"))
}
}

//noinspection GroovyAssignabilityCheck,GrUnresolvedAccess
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
//noinspection GrUnresolvedAccess
Expand Down
6 changes: 5 additions & 1 deletion resources/META-INF/changelog.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ <h1>v19.0.1</h1>
<li>
<p>Enhancements</p>
<ul>
<li>
<li>
<a href="https://github.com/KronicDeth/intellij-elixir/pull/3639">
#3639 Support JetBrains Exception Analyzer
</a> - <a href="https://github.com/joshuataylor">@joshuataylor</a>
</li><li>
<a href="https://github.com/KronicDeth/intellij-elixir/pull/3643">
#3643 Fix RubyMine freezing for umbrella projects but showing the new project wizard as a temporary workaround.
</a> - <a href="https://github.com/joshuataylor">@joshuataylor</a>
</li>
</ul>
</li>
Expand Down
33 changes: 21 additions & 12 deletions src/org/elixir_lang/Elixir.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@ object Elixir {
environment: Map<String, String>,
workingDirectory: String?,
elixirSdk: Sdk,
erlArgumentList: kotlin.collections.List<String> = emptyList()
erlArgumentList: kotlin.collections.List<String> = emptyList(),
): GeneralCommandLine {
val erlangSdk = elixirSdkToEnsuredErlangSdk(elixirSdk)
val commandLine = org.elixir_lang.Erl.commandLine(
pty = false,
environment = environment,
workingDirectory = workingDirectory,
erlangSdk = erlangSdk
)
val commandLine =
org.elixir_lang.Erl.commandLine(
pty = false,
environment = environment,
workingDirectory = workingDirectory,
erlangSdk = erlangSdk,
)
// MUST be before `addElixir` because it ends with `-extra` which turns off argument parsing for `erl`
commandLine.addParameters(erlArgumentList)
addElixir(commandLine, elixirSdk, erlangSdk)
Expand All @@ -35,13 +36,17 @@ object Elixir {
?: throw MissingErlangSdk(elixirSdk)

fun elixirSdkHasErlangSdk(elixirSdk: Sdk): Boolean = elixirSdkToErlangSdk(elixirSdk) != null
fun elixirSdkToErlangSdk(elixirSdk: Sdk): Sdk? =
elixirSdk.sdkAdditionalData?.let { it as SdkAdditionalData }?.erlangSdk

fun elixirSdkToErlangSdk(elixirSdk: Sdk): Sdk? = elixirSdk.sdkAdditionalData?.let { it as SdkAdditionalData }?.getErlangSdk()

/**
* Adds `-pa ebinDirectory` for those in the `elixirSdk` that aren't in the `erlangSdk`
*/
fun prependNewCodePaths(commandLine: GeneralCommandLine, elixirSdk: Sdk, erlangSdk: Sdk) {
fun prependNewCodePaths(
commandLine: GeneralCommandLine,
elixirSdk: Sdk,
erlangSdk: Sdk,
) {
val elixirEbinDirectories = elixirSdk.ebinDirectories()
val erlangEbinDirectories = erlangSdk.ebinDirectories()
prependNewCodePaths(commandLine, elixirEbinDirectories, erlangEbinDirectories)
Expand All @@ -50,7 +55,11 @@ object Elixir {
/**
* Keep in-suync with [org.elixir_lang.jps.Builder.addElixir]
*/
private fun addElixir(commandLine: GeneralCommandLine, elixirSdk: Sdk, erlangSdk: Sdk) {
private fun addElixir(
commandLine: GeneralCommandLine,
elixirSdk: Sdk,
erlangSdk: Sdk,
) {
prependNewCodePaths(commandLine, elixirSdk, erlangSdk)
commandLine.addParameters("-noshell", "-s", "elixir", "start_cli")
commandLine.addParameters("-elixir", "ansi_enabled", "true")
Expand All @@ -60,7 +69,7 @@ object Elixir {
private fun prependNewCodePaths(
commandLine: GeneralCommandLine,
elixirEbinDirectories: kotlin.collections.List<String>,
erlangEbinDirectories: kotlin.collections.List<String>
erlangEbinDirectories: kotlin.collections.List<String>,
) {
val newEbinDirectories = elixirEbinDirectories - erlangEbinDirectories
prependCodePaths(commandLine, newEbinDirectories)
Expand Down
2 changes: 1 addition & 1 deletion src/org/elixir_lang/facet/configurable/Provider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ import com.intellij.openapi.options.ConfigurableProvider
import org.elixir_lang.sdk.ProcessOutput

class Provider(private val project: com.intellij.openapi.project.Project): ConfigurableProvider() {
override fun canCreateConfigurable(): Boolean = ProcessOutput.isSmallIde()
override fun canCreateConfigurable(): Boolean = ProcessOutput.isSmallIde
override fun createConfigurable(): Configurable = Project(project)
}
2 changes: 1 addition & 1 deletion src/org/elixir_lang/facet/sdks/Provider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import com.intellij.openapi.options.ConfigurableProvider
import org.elixir_lang.sdk.ProcessOutput

abstract class Provider : ConfigurableProvider() {
override fun canCreateConfigurable(): Boolean = ProcessOutput.isSmallIde()
override fun canCreateConfigurable(): Boolean = ProcessOutput.isSmallIde
}
4 changes: 4 additions & 0 deletions src/org/elixir_lang/mix/Project.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.elixir_lang.mix

import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.module.ModifiableModuleModel
import com.intellij.openapi.module.Module
import com.intellij.openapi.progress.ProgressIndicator
Expand All @@ -20,6 +21,8 @@ import java.io.EOFException
import java.io.File

object Project {
private val LOG = Logger.getInstance(Project::class.java)

fun addSourceDirToContent(
content: ContentEntry,
root: VirtualFile,
Expand All @@ -41,6 +44,7 @@ object Project {

VfsUtilCore.visitChildrenRecursively(root, object : VirtualFileVisitor<Any>() {
override fun visitFile(file: VirtualFile): Boolean {
LOG.debug("visiting $file")
indicator.checkCanceled()

if (file.isDirectory) {
Expand Down
55 changes: 53 additions & 2 deletions src/org/elixir_lang/mix/project/DirectoryConfigurator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import com.intellij.facet.FacetManager
import com.intellij.facet.FacetType
import com.intellij.facet.impl.FacetUtil.addFacet
import com.intellij.ide.impl.OpenProjectTask
import com.intellij.notification.NotificationGroupManager
import com.intellij.notification.NotificationType
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.progress.ProgressIndicator
Expand All @@ -13,47 +16,82 @@ import com.intellij.openapi.progress.Task
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ex.ProjectManagerEx
import com.intellij.openapi.roots.ModuleRootModificationUtil
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable
import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel
import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.PlatformProjectOpenProcessor.Companion.runDirectoryProjectConfigurators
import com.intellij.projectImport.ProjectAttachProcessor
import com.intellij.util.PlatformUtils
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeout
import org.elixir_lang.DepsWatcher
import org.elixir_lang.Facet
import org.elixir_lang.mix.Project.addFolders
import org.elixir_lang.mix.Watcher
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.io.path.exists
import org.elixir_lang.sdk.elixir.Type

/**
* Used in Small IDEs like Rubymine that don't support [OpenProcessor].
*/
class DirectoryConfigurator : com.intellij.platform.DirectoryProjectConfigurator {
companion object {
private val LOG = Logger.getInstance(DirectoryConfigurator::class.java)
}

override fun configureProject(
project: Project,
baseDir: VirtualFile,
moduleRef: Ref<Module>,
isProjectCreatedWithWizard: Boolean
) {
var foundOtpApps: List<OtpApp> = emptyList()
LOG.debug("configuring $baseDir for project $project, created with wizard: $isProjectCreatedWithWizard")

ProgressManager.getInstance().run(object : Task.Modal(project, "Scanning Mix Projects", true) {
override fun run(indicator: ProgressIndicator) {
foundOtpApps = org.elixir_lang.mix.Project.findOtpApps(baseDir, indicator)
}
})

// If this is an umbrella app, RubyMine currently freezes.
// Instead, let's just show a notification that the user needs to use the Wizard.
if (!isProjectCreatedWithWizard && foundOtpApps.isNotEmpty() && foundOtpApps.size > 1) {
LOG.info("not configuring project $project because it is an umbrella app")
NotificationGroupManager.getInstance()
.getNotificationGroup("Elixir")
.createNotification(
"Umbrella App Detected",
"Elixir Umbrella app detected, please use the Project Wizard to properly configure it when using an IDE like RubyMine.",
NotificationType.WARNING
)
.notify(project)

return
}

for (otpApp in foundOtpApps) {
LOG.debug("configuring descendant otp app: ${otpApp.name}")
if (otpApp.root == baseDir) {
LOG.debug("configuring root otp app: ${otpApp.name}")
configureRootOtpApp(project, otpApp)
} else {
runBlocking {
launch(coroutineContext) {
configureDescendantOtpApp(project, otpApp)
try {
withTimeout(2000L) {
LOG.debug("Not otp app root: ${otpApp.name}, configuring descendant otp app.")
configureDescendantOtpApp(project, otpApp)
}
} catch (e: TimeoutCancellationException) {
// Handle the timeout exception, e.g., log a warning or notify the user
LOG.error("Timeout while configuring descendant OTP app: ${otpApp.name}", e)
}
}
}
Expand Down Expand Up @@ -82,8 +120,10 @@ class DirectoryConfigurator : com.intellij.platform.DirectoryProjectConfigurator
private suspend fun configureDescendantOtpApp(rootProject: Project, otpApp: OtpApp) {
if (!PlatformUtils.isGoIde() && ProjectAttachProcessor.canAttachToProject()) {
newProject(otpApp)?.let { otpAppProject ->
LOG.debug("attaching $otpAppProject to $rootProject")
attachToProject(rootProject, Paths.get(otpApp.root.path))

LOG.debug("scanning libraries for newly attached project for OTP app ${otpApp.name}")
ProgressManager.getInstance().run(object : Task.Modal(
otpAppProject,
"Scanning mix.exs to connect libraries for newly attached project for OTP app ${otpApp.name}",
Expand All @@ -92,8 +132,10 @@ class DirectoryConfigurator : com.intellij.platform.DirectoryProjectConfigurator
override fun run(progressIndicator: ProgressIndicator) {
for (module in ModuleManager.getInstance(otpAppProject).modules) {
if (progressIndicator.isCanceled) {
LOG.debug("canceled scanning libraries for newly attached project for OTP app ${otpApp.name}")
break
}
LOG.debug("scanning libraries for newly attached project for OTP app ${otpApp.name} for module ${module.name}")

Watcher(otpAppProject).syncLibraries(module, progressIndicator)
}
Expand All @@ -108,8 +150,10 @@ class DirectoryConfigurator : com.intellij.platform.DirectoryProjectConfigurator
*/
private suspend fun newProject(otpApp: OtpApp): Project? {
val projectDir = Paths.get(FileUtil.toSystemDependentName(otpApp.root.path), Project.DIRECTORY_STORE_FOLDER)
LOG.debug("Checking if $projectDir exists")

return if (projectDir.exists()) {
LOG.debug("$projectDir already exists")
null
} else {
val path = otpApp.root.path.let { Paths.get(it) }
Expand All @@ -119,16 +163,23 @@ class DirectoryConfigurator : com.intellij.platform.DirectoryProjectConfigurator
projectName = otpApp.name
}

LOG.debug("Creating new project at $path with isNewProject: ${openProjectTask.isNewProject} and useDefaultProjectAsTemplate: ${openProjectTask.useDefaultProjectAsTemplate} and projectName: ${openProjectTask.projectName}")

ProjectManagerEx
.getInstanceEx()
.newProject(
path,
openProjectTask
)
?.let { project ->
LOG.debug("runDirectoryProjectConfigurators for project: $project at $path")
runDirectoryProjectConfigurators(path, project, false)
LOG.debug("runDirectoryProjectConfigurators complete for project: $project at $path")

LOG.debug("Saving settings for project: $project at $path")

StoreUtil.saveSettings(project, true)
LOG.debug("Saved settings for project: $project at $path")

project
}
Expand Down
2 changes: 0 additions & 2 deletions src/org/elixir_lang/notification/setup_sdk/Action.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleType
import com.intellij.openapi.project.Project
import org.elixir_lang.notification.setup_sdk.Provider.Companion.showFacetSettings
import org.elixir_lang.notification.setup_sdk.Provider.Companion.showModuleSettings

/**
* Created by zyuyou on 15/7/8.
Expand Down
Loading

0 comments on commit b698fda

Please sign in to comment.