Problems adding modules from Project Structure

My Clojure plugin has an integration with Leiningen, which is a Maven-like build tool for Clojure. One thing that I can't get to work correctly is importing new modules from the project structure dialog. Leiningen is famously slow to start up, and its build file is not declarative so I have to invoke it to get the project details for a new module. This can take 5-10 seconds, so I don't want to block the UI while that is happening. I invoke lein in a background task which works fine for all use cases except this one - ProjectImportBuilder.commit() requires me to return a list of the created modules.

I've tried various approaches here, either creating temporary modules which will later be updated by the asynchronous project sync, or returning an empty list and just allowing the modules to be created later, but I can't get the project structure UI to update with the later changes that happen when the project is finally synchronised. Even if I create everything using the passed modifiable models (via an IdeModifiableModelsProvider), the UI doesn't update. I've also tried obtaining the ModulesConfigurator via the ProjectStructureConfigurable when it exists and the UI is active, but I can't seem to get it to refresh the UI.

Is there any way to achieve this?

4 comments
Comment actions Permalink

The optimal approach is to use IntelliJ external system API. Most of such issues (related to integration with different build tools) have been already addressed .

The import from the Project Structure Dialog should be performed using `IdeUIModifiableModelsProvider`. That way committed IDE project models can be discarded when the user close the dialog using 'Cancel' button after the import. And as you noticed the import should be synchronous and fast.

These requirements can be implemented using  `com.intellij.openapi.externalSystem.service.project.wizard.AbstractExternalProjectImportBuilder`. You can find the gradle implementation of the class at https://github.com/JetBrains/intellij-community/blob/171/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/wizard/GradleProjectImportBuilder.java 

It runs the project import twice:

1. Using the preview mode. It's the synchronous call.
E.g. in the gradle plugin I decided not to call gradle at all to build the project preview model. See details at https://github.com/JetBrains/intellij-community/blob/171/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java#L114-L130 

2. The full project import. It will be run after the Project Structure Dialog will be closed in the background.

 

0
Comment actions Permalink

Thanks for the quick reply, Vladislav. Yes, I would really like to use the external system API, unfortunately the Lein integration was written before that existed and it's a big job to migrate it now. I definitely plan to at some stage, though.

I'm using IdeUIModifiableModelsProvider when commit() is called from the UI, so that should be ok. 

So it looks like in your project resolver, when it's called in preview mode you just create a module with the appropriate content root and nothing else, is that correct? That's essentially what I'm doing now, but I'm manually creating the temporary module.

One thing I'm doing at the moment is I'm doing the full resolve asynchronously in the background after commit() is called, and that causes problems since the UI partially updates but the module editors do not. It would be better to do it when the Project Structure dialog is changed, can you point me to how I would achieve that?

0
Comment actions Permalink

Thanks Vladislav, I didn't know I could use NON_MODAL like that - that's useful.

0

Please sign in to leave a comment.