Accessing settings.gradle object from com.intellij.openapi.project.Project

intellij {
type.set(“IC”) // Target IDE Platform
version.set(“2024.1.7”)
}
I’m trying to extend the settings.gradle configuration in an IntelliJ plugin. In Gradle, this is done via project.extensions.create("myExtension", MyExtension.class). However, I need to achieve this using the IntelliJ Platform API.

Could you please clarify:

  1. How to obtain the SettingsGradle object instance from a com.intellij.openapi.project.Project instance?
  2. What is the correct way to register custom extensions for settings.gradle in IntelliJ Platform?
1 Like

Hi @ChenChen-Engine,
I am not sure if I completely understand what you mean by extending settings.gradle configuration. Unfortunately, I don’t see it possible to apply a Gradle Extension to your script directly from an IntelliJ plugin code. Did you try applying your extensions using Gradle init scripts?

If you could achieve the desirable result using an init script, most probably it’s possible to apply the init script from an IntelliJ plugin. However, in this case, it should be noted that if you need to interact with a Gradle project NOT from IDEA (e.g. via command line), then you should apply the init script somehow else (see Invoking an init script).

I haven’t tried Gradle init scripts yet. After a brief look at the documentation links you provided, they don’t seem to meet my needs. What I want is to provide an extension for plugin users in their build.gradle or settings.gradle files to collect the required information, similar to:

android {
    namespace "xxx.xxx.xx"
}

I noticed other solutions, such as creating a form interface for the plugin, which could also collect the necessary information. However, I prefer collecting it within the build.gradle file.

I also came across an API:

org.jetbrains.plugins.gradle.service.resolve.GradleExtensionsContributor.getExtensionsFor(file).extensions

It seems that by putting an extension into it, I can achieve the desired functionality. However, currently, GradleExtensionsContributor.getExtensionsFor(file) returns empty, maybe the timing is not right.

Hi @ChenChen-Engine,

An init script like the below could provide an extension in build.gradle:

// $GRADLE_USER_HOME/init.d/myAndroidExtension.init.gradle
class AndroidExtension {
    String namespace = "myNamespace"
}

allprojects {
    extensions.create("android", AndroidExtension)
}

This makes it possible to use the extension in build.gradle:

android {
    namespace = "xxx.xxx.xx"
}

tasks.register("printAndroidNamespace") {
    doLast {
        println("Android namespace: " + android.namespace)
    }
}

In this example, the init script is located in $GRADLE_USER_HOME, so it is applied to all projects. You also could locate it somewhere else and apply it when using the Gradle command line tool:

gradle --init-script myAndroidExtension.init.gradle printAndroidNamespace

Does this example seem like what you need?

This method indeed is able to provide available extensions for a given file. However, the access is read-only. This method could be used in IDEA for auto-complete for example.

I don’t see it possible to add an extension to Gradle scripts without changing any scripts that Gradle reads. Not just from an IntelliJ plugin, but in general.

I’m glad you can confirm the purpose of this API.Can I add an extension and then try synchronizing this Gradle file for it to take effect?

I’m not sure, but I want to try. I think this is the most suitable solution for me. Can you tell me which extension point callback to call this method to get the value correctly

org.jetbrains.plugins.gradle.service.resolve.GradleExtensionsContributor.getExtensionsFor(file).extensions

Could you please elaborate on:

  • where do you want to add an extension? In Gradle script (e.g. via project.extensions.create("myExtension", MyExtension.class))?
  • what do you mean by try synchronizing this Gradle file?
  • what effect are you expecting to take?

Sorry, I am a bit confused. Probably, I don’t understand what solution you are looking for. What are you trying to achieve with this API?

If I correctly understood your topic message:

… you want to apply an extension to a Gradle script from IntelliJ Plugin. However, as I said, this API is not able to do this.

GradleExtensionsContributor.getExtensionsFor(file).extensions has read-only access to extensions available for a build script. It just provides class names of the extensions, but not the data stored in the instances of these classes. Moreover, this method cannot change data in extensions or add extensions.

For example with an init script from my comment above, this method would show only this data about the extensions available for the build script.


It shows only the name of the extension and the corresponding class name. Would having such information be a solution for you?

Let me outline the functionality I want to implement in this plugin:

Due to compilation rules, AModule depends on BModule. When BModule is modified, AModule also gets recompiled. As I’m not deeply familiar with compilation principles, I’m unsure whether modifying elements in BModule that aren’t referenced by AModule would still trigger recompilation.

I want to develop a plugin to decouple this dependency relationship. Simply specify the target module to the plugin, and it will intelligently auto-complete classes, functions, and properties from that module.

Here are my ideas and implementation steps:

  1. Annotation Collection: Have developers provide fully qualified annotation names for analysis. The preferred method would be collecting them in the project’s settings.gradle, like:

// settings.gradle

autoCompletionAnnotation {

annotation = "xx.xx.Xxx"

}

(I’m not sure if this is the best approach - alternative suggestions are welcome)

  1. Module Declaration:Let developers specify target modules for smart completion in build files:

// AModule.build.gradle

autoCompleteModules {

modules = ":BModule"

}

  1. PSI Analysis: Analyze com.intellij.psi.PsiElement to find annotated class, function, and property declarations, then add them to com.intellij.codeInsight.completion.CompletionResultSet.

  2. Error Suppression: Since AModule and BModule would lack dependency relationships, IDE code analysis would flag “unresolved reference” errors. The plugin needs to suppress these false errors and validate the code correctness.

  3. Navigation Handling: Uncertain whether fixing error hints would enable proper source code navigation. If not, additional navigation handling would be required.

  4. Compilation Compatibility: Unsure if compilation issues might persist. Any remaining problems could be addressed incrementally.

This is my idea for this plugin. I have never developed an intellij plugin before, so my description of the problem may not be accurate, but I will try my best to express it clearly

I have previously learned about some Kotlin Compiler Plugin, which can make arbitrary modifications to files. I believe the Idea plugin should also be able to do so

I am also not deeply familiar with compilation process details, so what are you going to implement seems to me like a challenging task. Especially, at these steps:

  1. decoupling the dependency relationship between modules and not breaking Gradle workflow by that. How actually are you going to decouple the dependency relationship? By not specifying the dependency on BModule in the build script of AModule?
  2. finally, setting up the compilation process to make possible the usage of BModule classes in AModule in runtime. How are you going to achieve that? With writing a custom Kotlin Compiler plugin?

I just want to make sure that you are not going to use the IntelliJ plugin for decoupling dependencies and setting up their re-coupling while compilation. In my understanding, these actions should be done through the changes in Gradle scripts.

The issue you mentioned is exactly the same one I’m currently trying to resolve, so I can’t provide an answer to your question right now.

I’ll look into potential solutions when I have time, though this will likely be a long-term process.

If there are any developments, I’ll be sure to share updates with you.

1 Like

I think, for the described desired functionality it’s really important to figure out with these compilation questions. Even if you implement an IntelliJ Plugin that adds resolving and navigation for references from AModule to the source code in BModule when the modules are decoupled, all this work will have little sense if the code does not compile properly. Good luck on your project!

Please let me know if you still have any questions related to writing an IntelliJ plugin for Gradle scripts.