Running Multiple Reformat Gradle Tasks Gives Error
Answered
I have a plugin where we are trying to change it to run its reformat action on save on multiple files at once.
We do this now by looping through all open files being saved, e.g.
for (Document document : documents) {
var file = PsiDocumentManager.getInstance(project).getPsiFile(document);
if (file == null) {
continue;
}
new ReformatCodeProcessor(file).run();
}
The actual gradle task execution is as follows:
// Constructs execution settings, setting the gradle task and its options
ExternalSystemTaskExecutionSettings settings = constructTaskExecutionSettings(fileToProcess);
// Execute gradle task
ExternalSystemUtil.runTask(settings, DefaultRunExecutor.EXECUTOR_ID, myProject, GradleConstants.SYSTEM_ID, null,
ProgressExecutionMode.IN_BACKGROUND_ASYNC, false);
However when testing this, we get the error:
Cannot use connection to Gradle distribution xxxx as it has been stopped.
See a reproduction of the issue here
Any idea how to fix this?
Please sign in to leave a comment.
How is the reformatting related to executing a Gradle task? When and where is that Gradle task triggered from?
Hi Yahn, sorry it wasn't more clear. The 'reformatting' is done through a spotless gradle task.
So the flow is the user kicks off an Action:
which then calls a processor:
This then calls the actual gradle task as shown above. Does that help clear things up?
There's dedicated hook to invoke external formatter, did you consider it? https://plugins.jetbrains.com/docs/intellij/code-formatting.html#external-code-formatter Not sure why you want to call it via Gradle.
Yann, I think it's because a lot of people already use Spotless Gradle , which includes features listed in that README such as:
It also allows for a lot of settings as shown here.
Even if this isn't necessarily the correct way to do it, using the external code formatter sounds like a new project outside the scope of spotless-intellij-gradle since we would have to implement these steps and the result would be more of a `spotless-intellij` project than a `spotless-intellij-gradle` project.
Could you help with how to fix this current problem of not being able to run multiple gradle tasks at once to unblock this format on save feature for this specific plugin which uses Spotless Gradle for the formatting? Or is that not possible?
Ryan Gurney what is the reason to call the formatter on per-file basis? Is not one invocation enough?
From what I see in the docs, the Gradle-Spotless plugin does not have file specific tasks, it always works per-project.
Also, Gradle does not officially support running multiple builds of same project in parallel.
As Yann Cebron already mentioned, the External Code Formatter API is a great place to call external tool to format the code. You can use same API ExternalSystemUtil.runTask there to invoke spotlessApply task
Nikita Skvortsov that's a very good point, and thanks for the response! Spotless actually does have file-specific functionality in the Gradle plugin using the ide hook, however right now it only supports one file. There is a request for that to change but I doubt it will be done in the near future. Running the gradle command without that flag would result in ALL files in the project being processed by the plugin, which would take a very long time and isn't really in the spirit of "format on save".
Perhaps all I can do right now is wait for the ide hook to support multiple files.
re: External Code Formatter -- what benefits does that give for running the gradle task as opposed to my current implementation running the task via an Action?
External Code Formatter benefits are not about running the gradle task (this code will stay the same), but about integrating into IDEA's ecosystem. Your formatter will be properly called on "Reformat Code..." action in IDEA, will respect Actions on Save configuration, will be able to get text ranges to format etc.
Nikita Skvortsov
Yann Cebron
I'm having some difficulty understanding exactly how this works. A couple of follow-up questions:
and nothing is run in that passed in lambda. Why does this not work here while it did in using the Action API instead of this External Formatter API?
I think the problem is the task never ends. On first invocation even though the reformatting is done and the gradle task complete, the progress bar still shows.
How do I signal the background task is complete to stop the formatting task?
I figured out #3 -- from reading the code I found it turns out you need to call `formattingRequest.onTextReady`...
For calling an exernal formatter please use AsyncDocumentFormattingServce. There's a number of flags telling when the formatter can be used, see FormattingService.Feauture. Note that due to asynchronous nature, it may not always work. For example, if there is a considerable delay during which the current document changes, nothing will happen because there's a conflict between the external formatter changes and the current document state. There's DocumentMerger extension point which can redefine this default behaviour. For example, you can simply replace the current document content with newText.
Hi Rustam Vishniakov, thank you for the response!
I actually am using AsyncDocumentFormattingService, however I _must_ have the formatting task be a gradle task -- this is required by the third party implementing the task. That being said, they offer a flag to pass in stdIn as the input and can give output through stdOut.
My outstanding questions are here. Any advice there would be appreciated!