@@ -5,6 +5,9 @@ import com.intellij.facet.FacetManager
5
5
import com.intellij.facet.FacetType
6
6
import com.intellij.facet.impl.FacetUtil.addFacet
7
7
import com.intellij.ide.impl.OpenProjectTask
8
+ import com.intellij.notification.NotificationGroupManager
9
+ import com.intellij.notification.NotificationType
10
+ import com.intellij.openapi.diagnostic.Logger
8
11
import com.intellij.openapi.module.Module
9
12
import com.intellij.openapi.module.ModuleManager
10
13
import com.intellij.openapi.progress.ProgressIndicator
@@ -13,47 +16,82 @@ import com.intellij.openapi.progress.Task
13
16
import com.intellij.openapi.project.Project
14
17
import com.intellij.openapi.project.ex.ProjectManagerEx
15
18
import com.intellij.openapi.roots.ModuleRootModificationUtil
19
+ import com.intellij.openapi.roots.ProjectRootManager
20
+ import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable
21
+ import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel
16
22
import com.intellij.openapi.util.Ref
17
23
import com.intellij.openapi.util.io.FileUtil
18
24
import com.intellij.openapi.vfs.VirtualFile
19
25
import com.intellij.platform.PlatformProjectOpenProcessor.Companion.runDirectoryProjectConfigurators
20
26
import com.intellij.projectImport.ProjectAttachProcessor
21
27
import com.intellij.util.PlatformUtils
28
+ import kotlinx.coroutines.TimeoutCancellationException
22
29
import kotlinx.coroutines.launch
23
30
import kotlinx.coroutines.runBlocking
31
+ import kotlinx.coroutines.withTimeout
24
32
import org.elixir_lang.DepsWatcher
25
33
import org.elixir_lang.Facet
26
34
import org.elixir_lang.mix.Project.addFolders
27
35
import org.elixir_lang.mix.Watcher
28
36
import java.nio.file.Path
29
37
import java.nio.file.Paths
30
38
import kotlin.io.path.exists
39
+ import org.elixir_lang.sdk.elixir.Type
31
40
32
41
/* *
33
42
* Used in Small IDEs like Rubymine that don't support [OpenProcessor].
34
43
*/
35
44
class DirectoryConfigurator : com.intellij.platform.DirectoryProjectConfigurator {
45
+ companion object {
46
+ private val LOG = Logger .getInstance(DirectoryConfigurator ::class .java)
47
+ }
48
+
36
49
override fun configureProject (
37
50
project : Project ,
38
51
baseDir : VirtualFile ,
39
52
moduleRef : Ref <Module >,
40
53
isProjectCreatedWithWizard : Boolean
41
54
) {
42
55
var foundOtpApps: List <OtpApp > = emptyList()
56
+ LOG .debug(" configuring $baseDir for project $project , created with wizard: $isProjectCreatedWithWizard " )
43
57
44
58
ProgressManager .getInstance().run (object : Task .Modal (project, " Scanning Mix Projects" , true ) {
45
59
override fun run (indicator : ProgressIndicator ) {
46
60
foundOtpApps = org.elixir_lang.mix.Project .findOtpApps(baseDir, indicator)
47
61
}
48
62
})
49
63
64
+ // If this is an umbrella app, RubyMine currently freezes.
65
+ // Instead, let's just show a notification that the user needs to use the Wizard.
66
+ if (! isProjectCreatedWithWizard && foundOtpApps.isNotEmpty() && foundOtpApps.size > 1 ) {
67
+ LOG .info(" not configuring project $project because it is an umbrella app" )
68
+ NotificationGroupManager .getInstance()
69
+ .getNotificationGroup(" Elixir" )
70
+ .createNotification(
71
+ " Umbrella App Detected" ,
72
+ " Elixir Umbrella app detected, please use the Project Wizard to properly configure it when using an IDE like RubyMine." ,
73
+ NotificationType .WARNING
74
+ )
75
+ .notify(project)
76
+
77
+ return
78
+ }
79
+
50
80
for (otpApp in foundOtpApps) {
81
+ LOG .debug(" configuring descendant otp app: ${otpApp.name} " )
51
82
if (otpApp.root == baseDir) {
83
+ LOG .debug(" configuring root otp app: ${otpApp.name} " )
52
84
configureRootOtpApp(project, otpApp)
53
85
} else {
54
86
runBlocking {
55
- launch(coroutineContext) {
56
- configureDescendantOtpApp(project, otpApp)
87
+ try {
88
+ withTimeout(2000L ) {
89
+ LOG .debug(" Not otp app root: ${otpApp.name} , configuring descendant otp app." )
90
+ configureDescendantOtpApp(project, otpApp)
91
+ }
92
+ } catch (e: TimeoutCancellationException ) {
93
+ // Handle the timeout exception, e.g., log a warning or notify the user
94
+ LOG .error(" Timeout while configuring descendant OTP app: ${otpApp.name} " , e)
57
95
}
58
96
}
59
97
}
@@ -82,8 +120,10 @@ class DirectoryConfigurator : com.intellij.platform.DirectoryProjectConfigurator
82
120
private suspend fun configureDescendantOtpApp (rootProject : Project , otpApp : OtpApp ) {
83
121
if (! PlatformUtils .isGoIde() && ProjectAttachProcessor .canAttachToProject()) {
84
122
newProject(otpApp)?.let { otpAppProject ->
123
+ LOG .debug(" attaching $otpAppProject to $rootProject " )
85
124
attachToProject(rootProject, Paths .get(otpApp.root.path))
86
125
126
+ LOG .debug(" scanning libraries for newly attached project for OTP app ${otpApp.name} " )
87
127
ProgressManager .getInstance().run (object : Task .Modal (
88
128
otpAppProject,
89
129
" Scanning mix.exs to connect libraries for newly attached project for OTP app ${otpApp.name} " ,
@@ -92,8 +132,10 @@ class DirectoryConfigurator : com.intellij.platform.DirectoryProjectConfigurator
92
132
override fun run (progressIndicator : ProgressIndicator ) {
93
133
for (module in ModuleManager .getInstance(otpAppProject).modules) {
94
134
if (progressIndicator.isCanceled) {
135
+ LOG .debug(" canceled scanning libraries for newly attached project for OTP app ${otpApp.name} " )
95
136
break
96
137
}
138
+ LOG .debug(" scanning libraries for newly attached project for OTP app ${otpApp.name} for module ${module.name} " )
97
139
98
140
Watcher (otpAppProject).syncLibraries(module, progressIndicator)
99
141
}
@@ -108,8 +150,10 @@ class DirectoryConfigurator : com.intellij.platform.DirectoryProjectConfigurator
108
150
*/
109
151
private suspend fun newProject (otpApp : OtpApp ): Project ? {
110
152
val projectDir = Paths .get(FileUtil .toSystemDependentName(otpApp.root.path), Project .DIRECTORY_STORE_FOLDER )
153
+ LOG .debug(" Checking if $projectDir exists" )
111
154
112
155
return if (projectDir.exists()) {
156
+ LOG .debug(" $projectDir already exists" )
113
157
null
114
158
} else {
115
159
val path = otpApp.root.path.let { Paths .get(it) }
@@ -119,16 +163,23 @@ class DirectoryConfigurator : com.intellij.platform.DirectoryProjectConfigurator
119
163
projectName = otpApp.name
120
164
}
121
165
166
+ LOG .debug(" Creating new project at $path with isNewProject: ${openProjectTask.isNewProject} and useDefaultProjectAsTemplate: ${openProjectTask.useDefaultProjectAsTemplate} and projectName: ${openProjectTask.projectName} " )
167
+
122
168
ProjectManagerEx
123
169
.getInstanceEx()
124
170
.newProject(
125
171
path,
126
172
openProjectTask
127
173
)
128
174
?.let { project ->
175
+ LOG .debug(" runDirectoryProjectConfigurators for project: $project at $path " )
129
176
runDirectoryProjectConfigurators(path, project, false )
177
+ LOG .debug(" runDirectoryProjectConfigurators complete for project: $project at $path " )
178
+
179
+ LOG .debug(" Saving settings for project: $project at $path " )
130
180
131
181
StoreUtil .saveSettings(project, true )
182
+ LOG .debug(" Saved settings for project: $project at $path " )
132
183
133
184
project
134
185
}
0 commit comments