Skip to content

Commit e5c96f8

Browse files
authored
Revert "Fix IntelliJ IDEA project open hang by removing FlutterProjec… (#8884)
…tOpenProcessor (#8846)" This reverts commit 4681015. The problem is seeing the open project dialog (the one below) twice upon creating a new project. <img width="447" height="165" alt="Screenshot 2026-04-01 at 8 59 27 PM" src="https://github.com/user-attachments/assets/69d08c92-3666-4ef2-87c3-2ff6c4c06aa5" />
1 parent b0d959e commit e5c96f8

4 files changed

Lines changed: 111 additions & 14 deletions

File tree

CHANGELOG.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
### Fixed
1818

19-
- Silent failure when opening Flutter projects without `.idea` directory in IntelliJ IDEA, by removing `FlutterProjectOpenProcessor` and
20-
migrating configuration logic to `FlutterInitializer`. (#8846)
2119
- Gutter buttons not running tests with non-ASCII characters in their names. (#7985)
2220
- Freeze from JX Browser close. (#8864)
2321
- Crash in split debugger mode in IntelliJ 2025.3+. (#8831)

resources/META-INF/plugin.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,8 @@
335335
<!-- See https://github.com/flutter/flutter-intellij/issues/8029 -->
336336
<projectService serviceImplementation="io.flutter.view.InspectorView" overrides="false"/>
337337

338+
<projectOpenProcessor id="flutter" implementation="io.flutter.project.FlutterProjectOpenProcessor" order="first"/>
339+
338340
<editorNotificationProvider implementation="io.flutter.editor.FlutterPubspecNotificationProvider"/>
339341
<editorNotificationProvider implementation="io.flutter.inspections.SdkConfigurationNotificationProvider"/>
340342
<editorNotificationProvider implementation="io.flutter.editor.NativeEditorNotificationProvider"/>

src/io/flutter/FlutterInitializer.java

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@
6767
* Runs actions after the project has started up and the index is up to date.
6868
*
6969
* @see ProjectOpenActivity for actions that run earlier.
70+
* @see io.flutter.project.FlutterProjectOpenProcessor for additional actions that
71+
* may run when a project is being imported.
7072
*/
7173
public class FlutterInitializer extends FlutterProjectActivity {
7274
private boolean toolWindowsInitialized = false;
@@ -97,18 +99,6 @@ public void executeProjectStartup(@NotNull Project project) {
9799
// Start a DevTools server
98100
DevToolsService.getInstance(project);
99101

100-
// Ensure Flutter project configuration is applied for projects that may have been
101-
// opened without a .idea directory. Previously this was handled by FlutterProjectOpenProcessor,
102-
// but that processor silently failed when no delegate processor could open the project.
103-
// Instead, we let the platform open the project normally and apply our configuration here.
104-
// See https://github.com/flutter/flutter-intellij/issues/8661 (Android Studio equivalent)
105-
for (Module module : FlutterModuleUtils.getModules(project)) {
106-
if (FlutterModuleUtils.declaresFlutter(module) && !FlutterModuleUtils.isFlutterModule(module)) {
107-
log().info("Fixing Flutter module configuration for " + module.getName());
108-
FlutterModuleUtils.setFlutterModuleAndReload(module, project);
109-
}
110-
}
111-
112102
// If the project declares a Flutter dependency, do some extra initialization.
113103
boolean hasFlutterModule = false;
114104

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright 2025 The Chromium Authors. All rights reserved.
3+
* Use of this source code is governed by a BSD-style license that can be
4+
* found in the LICENSE file.
5+
*/
6+
package io.flutter.project
7+
8+
import com.intellij.openapi.project.Project
9+
import com.intellij.openapi.vfs.VirtualFile
10+
import com.intellij.projectImport.ProjectOpenProcessor
11+
import icons.FlutterIcons
12+
import io.flutter.FlutterBundle
13+
import io.flutter.FlutterUtils
14+
import io.flutter.pub.PubRoot
15+
import io.flutter.utils.FlutterModuleUtils
16+
import java.util.*
17+
import javax.swing.Icon
18+
19+
/**
20+
* Originally `FlutterProjectOpenProcessor.java`.
21+
*
22+
* This processor handles opening Flutter projects when they are selected directly (e.g. via "Open" in the IDE).
23+
* It delegates the actual opening to the platform's default processor (e.g. Gradle or Maven processor if applicable,
24+
* or the generic project opener) and then ensures that any modules in the project are correctly configured as Flutter modules.
25+
*
26+
* Converted to Kotlin to support `openProjectAsync` which is a suspend function.
27+
*/
28+
open class FlutterProjectOpenProcessor : ProjectOpenProcessor() {
29+
override val name: String
30+
get() = FlutterBundle.message("flutter.module.name")
31+
32+
override fun getIcon(file: VirtualFile): Icon? {
33+
return FlutterIcons.Flutter
34+
}
35+
36+
override fun canOpenProject(file: VirtualFile): Boolean {
37+
if (FlutterUtils.isAndroidStudio()) {
38+
return false
39+
}
40+
val root = PubRoot.forDirectory(file)
41+
return root != null && root.declaresFlutter()
42+
}
43+
44+
/**
45+
* Replaces the deprecated `doOpenProject`.
46+
*
47+
* This method is `suspend` and must be used instead of `doOpenProject` to avoid `IllegalStateException` in newer IDE versions.
48+
*
49+
* It performs the following steps:
50+
* 1. Finds a delegate processor (e.g. Gradle) to open the project.
51+
* 2. Opens the project asynchronously.
52+
* 3. Once opened, checks if the project contains Flutter modules that are not yet configured as such (e.g. missing module type).
53+
* 4. Configures these modules as Flutter modules within a write action.
54+
*/
55+
override suspend fun openProjectAsync(
56+
virtualFile: VirtualFile,
57+
projectToClose: Project?,
58+
forceOpenInNewFrame: Boolean,
59+
): Project? {
60+
// Delegate opening to the platform open processor.
61+
val importProvider = getDelegateImportProvider(virtualFile) ?: return null
62+
val project = importProvider.openProjectAsync(virtualFile, projectToClose, forceOpenInNewFrame)
63+
if (project == null || project.isDisposed) return project
64+
65+
// Convert any modules that use Flutter but don't have IntelliJ Flutter metadata.
66+
convertToFlutterProject(project)
67+
68+
return project
69+
}
70+
71+
/**
72+
* Deprecated method, kept to satisfy the compiler/interface.
73+
*
74+
* We return `null` to indicate that this processor does not support the synchronous opening method
75+
* and that `openProjectAsync` should be used instead.
76+
*/
77+
override fun doOpenProject(
78+
virtualFile: VirtualFile,
79+
projectToClose: Project?,
80+
forceOpenInNewFrame: Boolean,
81+
): Project? {
82+
return null
83+
}
84+
85+
protected open fun getDelegateImportProvider(file: VirtualFile): ProjectOpenProcessor? {
86+
return EXTENSION_POINT_NAME.extensionList.stream().filter { processor: ProjectOpenProcessor ->
87+
processor.canOpenProject(file) && !Objects.equals(
88+
processor.name,
89+
name
90+
)
91+
}.findFirst().orElse(null)
92+
}
93+
}
94+
95+
/**
96+
* Sets up a project that doesn't have any Flutter modules.
97+
*
98+
*
99+
* (It probably wasn't created with "flutter create" and probably didn't have any IntelliJ configuration before.)
100+
*/
101+
private fun convertToFlutterProject(project: Project) {
102+
for (module in FlutterModuleUtils.getModules(project)) {
103+
if (FlutterModuleUtils.declaresFlutter(module) && !FlutterModuleUtils.isFlutterModule(module)) {
104+
FlutterModuleUtils.setFlutterModuleAndReload(module, project)
105+
}
106+
}
107+
}

0 commit comments

Comments
 (0)