This section focuses on explaining coroutines in the specific context of the IntelliJ Platform. If you are not experienced with Kotlin Coroutines, it is highly recommended to get familiar with Learning Resources first.
In the IntelliJ Platform, coroutines can be launched with one of the following approaches:
The currentThreadCoroutineScope
function for executing actions.
The runBlockingCancellable
function. (not recommended)
The recommended approach is creating a service that receives its scope via the constructor injection and launching a coroutine from the service methods. Note that while creating a service instance does allocate additional resources, using a dedicated service and scope remains a lightweight and fundamentally safe solution for launching coroutines. It should be used whenever possible.
The pattern is as follows:
@Service class MyApplicationService( private val cs: CoroutineScope ) { fun scheduleSomething() { cs.launch { // do something } } }
@Service(Service.Level.PROJECT) class MyProjectService( private val project: Project, private val cs: CoroutineScope ) { fun scheduleSomething() { cs.launch { // do something } } }
The injected scope is created per service, so each instance has its own isolated scope with a common parent, which is an intersection scope. The injected scope is canceled when the container (application/project) is shut down or when the plugin is unloaded.
UsingcurrentThreadCoroutineScope
Action behavior performed in AnAction.actionPerformed()
can be executed in a coroutine via currentThreadCoroutineScope
:
internal class MyAction : AnAction() { override fun actionPerformed(e: AnActionEvent) { val file = e.getData(LangDataKeys.PSI_FILE) ?: return currentThreadCoroutineScope().launch { // use suspending APIs: val targets = readAction { // do something in read } withContext(Dispatchers.EDT) { // show some UI } } } // ... }
Compared to the service scope approach, using currentThreadCoroutineScope()
enables Action System infrastructure to control the launched coroutine and cancel it if needed. In the case of service scopes, the infrastructure code can't control a coroutine launched from an action, as service scopes are "more global" and live longer than the action trigger.
runBlockingCancellable
Using runBlockingCancellable
is not recommended. Use service scopes whenever possible.
In a standard coroutine-based application, the bridge between the regular blocking code and the suspending code is the runBlocking
function.
In the IntelliJ Platform, a similar purpose is achieved by the runBlockingCancellable
function. In addition to the same semantics as runBlocking
, the action gets canceled when the current progress indicator or the current job is canceled.
If a topic is not covered in the above sections, let us know via the Was this page helpful? feedback form below or other channels.
Be specific about the topics and reasons for adding them and leave your email in case we need more details. Thanks for your feedback!
11 August 2025
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4