KEMBAR78
JetBrains Platform : Plugin and extension development for JetBrains products. | The JetBrains Blog https://blog.jetbrains.com Developer Tools for Professionals and Teams Thu, 16 Oct 2025 21:38:59 +0000 en-US hourly 1 https://blog.jetbrains.com/wp-content/uploads/2024/01/cropped-mstile-310x310-1-32x32.png JetBrains Platform : Plugin and extension development for JetBrains products. | The JetBrains Blog https://blog.jetbrains.com 32 32 JetBrains Plugin Developer Conf 2025 Is Coming Up Soon! https://blog.jetbrains.com/platform/2025/10/jetbrains-plugin-developer-conf-2025-is-coming-up-soon/ Thu, 16 Oct 2025 21:38:13 +0000 https://blog.jetbrains.com/wp-content/uploads/2025/10/Plugin-Dev-Conf-25_Featured_Blog_1280x720.png https://blog.jetbrains.com/?post_type=platform&p=651276 Hey everyone! We’re excited to announce that JetBrains Plugin Developer Conf returns this November. Join us on Wednesday, November 5 for a full day of inspiring talks, live Q&A sessions, and deep dives into the latest in plugin development.

Whether you’re just getting started or already publishing on JetBrains Marketplace, you’ll find new ideas, practical techniques, and stories from plugin developers who’ve been there.

The talks on this year’s agenda include:

  • Keynote by Ivan Chirkov, Jakub Chrzanowski, and Robert Novotny
  • From Template to Marketplace: Creating Your First Plugin by Dmitrii Derepko
  • Developing a Language Plugin: LSP Versus the Joy of Learning by Aleksandr Slepchenkov
  • Kotlin Notebook Meets IntelliJ Platform by Jakub Chrzanowski
  • Building in Constrained Environments: Lessons From YouTrack Apps by Tommaso Gionfriddo
  • AI-Powered Test Generation Straight From Your Debugger by Michael Solovev
  • Making an IntelliJ Plugin Remote Development-Friendly by Nikita Katkov
  • How to Investigate UI Freezes by Konstantin Nisht

You can choose whether to attend just a few individual sessions or watch every one of them. We hope you enjoy the talks, and we encourage you to ask questions!

We’ll stream the presentations live on YouTube, and all the sessions will remain available after the event is over so you can catch up on any you missed. 

]]>
Islands Theme: The New Look Coming to JetBrains IDEs https://blog.jetbrains.com/platform/2025/09/islands-theme-the-new-look-coming-to-jetbrains-ides/ Mon, 22 Sep 2025 16:24:54 +0000 https://blog.jetbrains.com/wp-content/uploads/2025/09/Islands-Theme.png https://blog.jetbrains.com/?post_type=platform&p=599368

Starting with version 2025.2.3, JetBrains IDEs will offer a new look: the Islands theme, available in both dark and light modes. This update is a visual refresh, which means that all functionality will remain the same. The new theme can be turned on or off in the Appearance settings.

This step brings us closer to our goal of making the Islands theme the default in the future, and on this mission, we’re taking an iterative and feedback-driven approach. We’re making small, focused improvements and sharing them early, with your feedback guiding our next steps.

With this update to the UI, we want to:

  • Provide a fresh, modern look that keeps pace with design trends.
  • Refine the previous UI update, implementing a clearer separation between the editor and tool windows, more prominent navigation, and better tab visibility.
  • Ensure consistency across JetBrains products, aligning JetBrains IDEs and the Toolbox App.

Landing on the Islands theme

During the 2025.2 EAP, we tested two design directions, and based on your feedback, we decided to move forward with what is now the Islands theme. 

To guide our decision, we combined results from mockup-based surveys, in-product A/B tests, user interviews, and usage statistics. This mix of qualitative and quantitative research helped us understand how each option worked in practice.

In the surveys and interviews, participants described the Islands theme as modern, clear, and easy to navigate, with better visual separation between the editor and tool windows. Many also appreciated the improved visibility of tabs and navigation elements. Overall, users were enthusiastic and ready to adopt the Islands theme as the default.

Here are some examples of the feedback we received:

  • It looks and feels modern and clean, helping me focus on my work.
  • Feels refreshing but it made way more obvious differentiating each section on the IDE. 
  • It has a fresh feel, the dark theme colors give a good contrast and it is easy to look at for a number of hours.

Your feedback also identified lots of things we can still improve on, and we’ll be working on them for the future releases.

We’re grateful to everyone who tried both new themes in those early stages and shared feedback. All of your responses, both supportive and critical, helped us make a more confident and informed decision.

Please share your feedback

The Islands theme is now available for everyone to try. If you enable it, you’ll get a survey invitation two days later. Please take a moment to share your thoughts. Your feedback makes a huge difference in our work to refine the design further.

As a thank-you, survey participants will be entered into a raffle for a chance to win either an Amazon Gift Card or a 1-year All Products Pack subscription.

Known issues

The Islands theme is in Beta, and we are still polishing some details and working to address known issues. Please vote and comment on the tickets that are most important to you, or submit a new issue if you notice something that isn’t on our radar.

]]>
Investigating IntelliJ Platform UI Freezes https://blog.jetbrains.com/platform/2025/09/investigating-intellij-platform-ui-freezes/ Tue, 09 Sep 2025 12:26:47 +0000 https://blog.jetbrains.com/wp-content/uploads/2025/09/IS-social-BlogFeatured-1280x720-2x.png https://blog.jetbrains.com/?post_type=platform&p=597137

You have probably seen this picture occasionally and wondered what is happening with your IDE and why it freezes! This is a tricky question, and many types of bugs and performance issues may lead to UI freezes.

JetBrains IDEs are built on top of a UI framework (the Java AWT) that uses a single thread, the event dispatch thread (EDT), to perform painting operations and process user input events.

A UI freeze occurs when the IDE cannot execute operations on the EDT, preventing interaction with the IDE. This blog tries to consolidate our knowledge about freezing reasons and causes. Use it to investigate and resolve UI freezes in your IDE plugins!

The IntelliJ Platform’s UI architecture

Because our UI frameworks are built on top of a single thread, it is important to keep the EDT from remaining blocked for a long time. The EDT runs an event loop that processes AWT events. Typical examples of these events are user input (such as typing or moving the mouse) and repaint requests from Swing.

Events need to be processed within 16 ms. Otherwise, the IDE is not able to render 60 frames per second.

Investigating UI freezes

In the vast majority of cases, simply looking at the thread dump will give you the information you need about a UI freeze. The investigation should start with the thread AWT-EventQueue-N – this is the EDT. Normally, its name should be AWT-EventQueue-0. If you see a bigger number in the suffix, there might be a platform issue.

In the event of a UI freeze, the EDT is usually blocked on some kind of lock.

Freezes caused by the read-write lock

If you are unfamiliar with the concept of the IntelliJ Platform’s read-write lock, you can learn more about it from this notebook.

Due to the IntelliJ Platform’s architecture, the write lock is often acquired on the EDT. Since it often isn’t possible to acquire the write lock immediately, you will sometimes see the following lines in the stack trace of the EDT:

"AWT-EventQueue-0" prio=0 tid=0x0 nid=0x0 waiting on condition
     java.lang.Thread.State: TIMED_WAITING
 on com.intellij.openapi.progress.util.EternalEventStealer@3a946cba
at java.base@21.0.8/java.lang.Object.wait0(Native Method)
...
(!) at com.intellij.platform.locking.impl.NestedLocksThreadingSupport$ComputationState.upgradeWritePermit(NestedLocksThreadingSupport.kt:370)
...
at com.intellij.platform.locking.impl.NestedLocksThreadingSupport.runWriteAction(NestedLocksThreadingSupport.kt:921)
...
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.kt:347)
...
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:92)

The key line here is marked with (!). This line indicates that the EDT is blocked on the acquisition of the write lock. In this case, there is no need to look above. The IntelliJ Platform usually enters emergency mode if it detects a UI freeze and runs some of its internal procedures.

The EDT being blocked on the write lock is a sign that a thread is running under the read lock. The next step in our investigation is to find this background thread. This can be done by searching for a substring readAction (case-insensitive) in the thread dump.

For example, we may find the following thread:

"JobScheduler FJ pool 1/11" prio=0 tid=0x0 nid=0x0 runnable
     java.lang.Thread.State: RUNNABLE

	at ai.grazie.rules.en.QuantifierNounCompatibility.<clinit>(QuantifierNounCompatibility.java:38)
	at ai.grazie.rules.en.AgreementSet.<clinit>(AgreementSet.java:42)
	at ai.grazie.rules.en.PluralsInCompounds.<clinit>(PluralsInCompounds.java:21)
	at ai.grazie.rules.en.Articles.<clinit>(Articles.java:250)
	...
	at ai.grazie.rules.toolkit.LanguageToolkit.allParameters(LanguageToolkit.java:87)
	(!!) at com.intellij.grazie.pro.TreeRuleChecker.calcParameters(TreeRuleChecker.java:234)
	...
	at com.intellij.codeInsight.daemon.impl.AnnotatorRunner$$Lambda/0x00000070047e8000.run(Unknown Source)
	...
	(!) at com.intellij.platform.locking.impl.NestedLocksThreadingSupport.tryRunReadAction(NestedLocksThreadingSupport.kt:826)
	...
	at java.base@21.0.8/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:187)

This thread is taken from ForkJoinPool, and we see that it is currently running a read action (at (!)). We also see AnnotatorRunner in the stack trace, which means that this thread is currently running highlighting. The read actions in highlighting are canceled on a pending write action, which means that the UI freeze is caused by the code not checking for ProgressManager.checkCanceled. In the middle of the block, we see some traces from the Grazie plugin (starting from (!!)). This concludes our investigation. We’ve found the problem – Grazie does not check for checkCanceled frequently enough, which causes the UI to freeze.

Freezes caused by a background write action

The IntelliJ Platform gradually moves write actions to background threads, but this functionality is currently unstable, and it can cause additional UI freezes and deadlocks.

While a write action can run in the background, the EDT still often acquires a write-intent lock, resulting in stack traces like the following:

"AWT-EventQueue-0" #91 [119043] prio=6 os_prio=31 cpu=71985.87ms elapsed=1065.05s tid=0x00000001610c4c00 nid=119043 sleeping [0x0000000398429000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep0(java.base@21.0.8/Native Method)
	...
	at com.intellij.platform.locking.impl.NestedLocksThreadingSupport$ComputationState.acquireWriteIntentPermit(NestedLocksThreadingSupport.kt:416)
	...
	at java.awt.EventDispatchThread.run(java.desktop/EventDispatchThread.java:92)

This means that the EDT cannot immediately acquire a write-intent lock. Our next step is to search for a write action. In this case, it may appear in coroutine dumps. For example:

- "RefreshQueue pool":StandaloneCoroutine{Active}, state: SUSPENDED [Kernel@lumrbnr1s12qelije7p5, Rete(abortOnError=false, commands=capacity=2147483647,data=[onReceive], reteState=kotlinx.coroutines.flow.StateFlowImpl@6d763516, dbSource=ReteDbSource(reteState=kotlinx.coroutines.flow.StateFlowImpl@6d763516)), DbSourceContextElement(kernel Kernel@lumrbnr1s12qelije7p5), ComponentManager(ApplicationImpl@106897812), com.intellij.codeWithMe.ClientIdContextElementPrecursor, Dispatchers.Default.limitedParallelism(1)]
	at com.intellij.core.rwmutex.WriteIntentPermitImpl.acquireWriteActionPermit(RWMutexIdea.kt:263)
	...
	at com.intellij.openapi.vfs.newvfs.RefreshQueueImpl.processEventsSuspending(RefreshQueueImpl.kt:191)
  ...
	at com.intellij.openapi.vfs.newvfs.RefreshQueueImpl$queueAsyncSessionWithCoroutines$3$1.invokeSuspend(RefreshQueueImpl.kt:177)

Here we see that a coroutine is SUSPENDED on acquisition of the write lock. In particular, VFS refresh cannot proceed, which means that a read action is alive. Indeed:

"JobScheduler FJ pool 7/9" #201 [175107] daemon prio=6 os_prio=31 cpu=153605.15ms elapsed=1039.57s tid=0x0000000142955a00 nid=175107 runnable  [0x00000003610e7000]
   java.lang.Thread.State: RUNNABLE
	at com.intellij.psi.impl.file.impl.MultiverseFileViewProviderCache.get(MultiverseFileViewProviderCache.kt:67)
	...
	at org.jetbrains.kotlin.idea.codeInsight.lineMarkers.KotlinRecursiveCallLineMarkerProvider.collectSlowLineMarkers(KotlinRecursiveCallLineMarkerProvider.kt:35)
	...
	at com.intellij.openapi.application.impl.ApplicationImpl.tryRunReadAction(ApplicationImpl.java:1206)
	...
	at java.util.concurrent.ForkJoinWorkerThread.run(java.base@21.0.8/ForkJoinWorkerThread.java:187)

Here we again arrive at the conclusion that some code cannot be canceled due to the read action. The process of resolving this freeze is similar to what we have discussed above.

SuvorovProgress

Sometimes the EDT is blocked in a class named SuvorovProgress:

"AWT-EventQueue-0" prio=0 tid=0x0 nid=0x0 waiting on condition
     java.lang.Thread.State: TIMED_WAITING
 on com.intellij.openapi.progress.util.EternalEventStealer@215bb938
	at java.base@21.0.7/java.lang.Object.wait0(Native Method)
	at java.base@21.0.7/java.lang.Object.wait(Object.java:366)
	at com.intellij.openapi.progress.util.EternalEventStealer.dispatchAllEventsForTimeout(SuvorovProgress.kt:261)
	at com.intellij.openapi.progress.util.SuvorovProgress.processInvocationEventsWithoutDialog(SuvorovProgress.kt:125)
	at com.intellij.openapi.progress.util.SuvorovProgress.dispatchEventsUntilComputationCompletes(SuvorovProgress.kt:73)
	at com.intellij.openapi.application.impl.ApplicationImpl.lambda$postInit$14(ApplicationImpl.java:1434)
	at com.intellij.openapi.application.impl.ApplicationImpl$$Lambda/0x000076ace059cff8.invoke(Unknown Source)
	at com.intellij.platform.locking.impl.RunSuspend.await(NestedLocksThreadingSupport.kt:1517)
	at com.intellij.platform.locking.impl.NestedLocksThreadingSupportKt.runSuspendWithWaitingConsumer(NestedLocksThreadingSupport.kt:1472)
	...
	at com.intellij.platform.locking.impl.NestedLocksThreadingSupport.runWriteAction(NestedLocksThreadingSupport.kt:921)
	...
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:92)

SuvorovProgress is merely a symptom of a UI freeze, however. It indicates that the IntelliJ Platform is in emergency mode, where it is still able to run certain trusted AWT events or draw a freeze popup UI.

It is very rarely a cause of a freeze, so the problem is likely somewhere else.

Freezes caused by thread starvation

The IntelliJ Platform uses the Kotlin Coroutines library a lot. In coroutines, there are two major thread pools: Dispatchers.Default and Dispatchers.IO. Both are bounded, with Dispatchers.Default containing as many threads as there are cores in your machine and Dispatchers.IO containing 64 threads. If all these threads are blocked on some operation, then the IDE encounters thread starvation – a situation where coroutine machinery cannot progress because all threads in a thread pool are blocked.

The usual symptom of thread starvation is coroutines being stuck in the Cancelling state. They cannot move into Cancelled because they cannot execute cleanup actions on their respective thread pools.

To investigate thread starvation of the Default dispatcher, you need to find all blocked threads that contain runDefaultDispatcherTask.

For example:

"DefaultDispatcher-worker-9@28483" daemon prio=5 tid=0xa0 nid=NA waiting
  java.lang.Thread.State: WAITING
	at jdk.internal.misc.Unsafe.park(Unsafe.java:-1)
	at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:269)
	...
	
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:48)
	at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source:1)
	(!!) at com.intellij.platform.pluginManager.frontend.BackendUiPluginManagerController.awaitForResult(BackendUiPluginManagerController.kt:293)
	...
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:610)
	(!) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runDefaultDispatcherTask(CoroutineScheduler.kt:882)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:906)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:775)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:762)

If there are as many such threads as cores in your machine (at (!)), then you have signs of thread starvation. Similarly, if you’re dealing with thread starvation of the IO dispatcher, you’ll have 64 blocked threads named DefaultDispatcher-worker-N.

NB: It is not enough to look at all threads that are named DefaultDispatcher-worker-N to conclude that there is thread starvation of the Default dispatcher. The coroutine scheduler shares physical threads between the Default and IO dispatchers, so it is difficult to say which thread belongs to which dispatcher without actually looking at the source code.

To fix thread starvation, blocking operations need to be moved out of the Default dispatcher. Here we see that runBlocking is used in the line with (!!), and it needs to be moved to a different dispatcher.

Freezes caused by service initialization

Another frequent source of locks in the IntelliJ Platform is service initialization. Since services are initialized once, a thread that tries to access a service can block while waiting for initialization on another thread.

Here’s an example of this scenario:

"AWT-EventQueue-0" #59 [128003] prio=6 os_prio=31 cpu=3011.23ms elapsed=172.40s tid=0x000000012c07ae00 nid=128003 waiting on condition  [0x000000039b0ae000]
   java.lang.Thread.State: TIMED_WAITING (parking)
	at jdk.internal.misc.Unsafe.park(java.base@21.0.7/Native Method)
	...
	(!) at com.intellij.serviceContainer.ComponentManagerImplKt.runBlockingInitialization$lambda$9(ComponentManagerImpl.kt:1660)
	...
	at com.intellij.serviceContainer.ComponentManagerImpl.getService(ComponentManagerImpl.kt:672)
	(!!) at com.intellij.xdebugger.XDebuggerManager.getInstance(XDebuggerManager.java:32)
	...
	(!!!) at com.intellij.platform.locking.impl.NestedLocksThreadingSupport.runWriteAction(NestedLocksThreadingSupport.kt:939)
	...
	at java.awt.EventDispatchThread.run(java.desktop/EventDispatchThread.java:92)

We see that the EDT is blocked on the initialization of a service in the line marked (!). The service is XDebuggerManager (at (!!)), so there might be something wrong inside it. Additionally, we note that this process is running under the write action (at (!!!)), an observation that will be useful later.

By searching for XDebuggerManager, we can find the following thread:

"DefaultDispatcher-worker-4" #55 [130051] daemon prio=5 os_prio=31 cpu=1537.10ms elapsed=172.41s tid=0x000000012b883c00 nid=130051 in Object.wait()  [0x000000036b607000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait0(java.base@21.0.7/Native Method)
	...
	(!) at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:1028)
	at com.intellij.xdebugger.impl.breakpoints.XBreakpointManagerImpl.loadState(XBreakpointManagerImpl.java:536)
	at com.intellij.xdebugger.impl.XDebuggerManagerImpl.loadState(XDebuggerManagerImpl.java:388)
	(!!) at com.intellij.xdebugger.impl.XDebuggerManagerImpl.loadState(XDebuggerManagerImpl.java:81)
	...
	at com.intellij.configurationStore.ComponentStoreWithExtraComponents.initComponentBlocking(ComponentStoreWithExtraComponents.kt:43)
	...
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:765)

The service instance initialization at (!!) tries to acquire the read lock (at (!)). The problem is clear – the write action on the EDT is blocked on the lock in service init, and service init is blocked on the read lock acquisition. This is a deadlock because of the incorrect order of the two locks.

The best way to fix it is to move the read action out of service initialization. If this is not possible, you can preload the service in the read action. This way, service initialization will inherit read access.

How to deal with runBlocking

Sometimes, you may notice that a thread is blocked in runBlocking. This means that it is trying to execute coroutines synchronously.

For example:

"JobScheduler FJ pool 6/15" prio=0 tid=0x0 nid=0x0 waiting on condition
     java.lang.Thread.State: TIMED_WAITING
 on kotlinx.coroutines.BlockingCoroutine@41813fd4
	at java.base@21.0.8/jdk.internal.misc.Unsafe.park(Native Method)
	...
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$BuildersKt__BuildersKt(Builders.kt:85)
	...
	(!) at com.intellij.openapi.progress.CoroutinesKt.runBlockingCancellable(coroutines.kt:117)
	at com.intellij.grazie.text.CheckerRunner.run(CheckerRunner.kt:53)
	...
	(!!) at com.intellij.openapi.application.impl.ApplicationImpl.tryRunReadAction(ApplicationImpl.java:1206)
	...
	at java.base@21.0.8/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:187)

First, we need to make sure that runBlockingCancellable is present (at (!)). This is a special platform version of runBlocking that works well with our cancellation machinery.

Since this thread runs the read action (at (!!)), we now need to figure out why it cannot be canceled. To do this, we need to look in the coroutine dump and search for the coroutine tree starting with BlockingCoroutine (this is the name of the coroutine corresponding to runBlocking). Here’s what we find:

- JobImpl{Active}
	- BlockingCoroutine{Active}@41813fd4, state: SUSPENDED [ModalityState.NON_MODAL, ComputationState(level=0,thisLevelLock=com.intellij.core.rwmutex.RWMutexIdeaImpl@1c825ccf,isParallelizedRead=true), BlockingEventLoop]
		at com.intellij.grazie.text.CheckerRunner$run$1.invokeSuspend(CheckerRunner.kt:69)
		- DeferredCoroutine{Active}, state: SUSPENDED [ModalityState.NON_MODAL, ComputationState(level=0,thisLevelLock=com.intellij.core.rwmutex.RWMutexIdeaImpl@1c825ccf,isParallelizedRead=true), BlockingEventLoop]
			at com.intellij.ml.grazie.pro.SentenceBatcher$forSentences$1.parseAsync(SentenceBatcher.kt:96)
			at com.intellij.ml.grazie.pro.CloudOrLocalBatchParser.parseAsync(CloudOrLocalBatchParser.kt:20)
			at com.intellij.ml.grazie.pro.ParsedSentence$Companion.getSentences(ParsedSentence.kt:104)
			at com.intellij.ml.grazie.pro.AsyncTreeRuleChecker.checkExternally$suspendImpl(AsyncTreeRuleChecker.kt:18)
			at com.intellij.ml.grazie.pro.AsyncTreeRuleChecker$Style.checkExternally(AsyncTreeRuleChecker.kt:48)
			at com.intellij.grazie.text.CheckerRunner$run$1$deferred$1$1.invokeSuspend(CheckerRunner.kt:56)

We see that this coroutine runs at com.intellij.grazie.text.CheckerRunner, which means that this BlockingCoroutine corresponds to runBlocking in the above trace. Now we can inspect the coroutine tree and try to find out the cause of the freeze.

Since the state of the coroutine is DeferredCoroutine{Active}, it is not canceled. This means something is wrong with cancellation in the platform, as the platform should cancel all read actions on an incoming write action; hence, all coroutines should also be canceled. Normally, we should see BlockingCoroutine{Cancelling} here. 

To fix this UI freeze, we need to figure out why the coroutine cannot transition to the {Cancelled} state. Most likely, the code does not call ProgressManager.checkCanceled() frequently enough.

Conclusion

In this blog post, we explored common sources of UI freezes in IDEs based on the IntelliJ Platform. Most often, the freezes are caused by insufficient cooperation between plugin code and the IntelliJ Platform. By using the IntelliJ Platform’s primitives for executing cancellable operations, we can greatly improve the responsiveness of JetBrains IDEs.

]]>
The LSP API Is Now Available to All IntelliJ IDEA Users and Plugin Developers https://blog.jetbrains.com/platform/2025/09/the-lsp-api-is-now-available-to-all-intellij-idea-users-and-plugin-developers/ Mon, 01 Sep 2025 09:02:50 +0000 https://blog.jetbrains.com/wp-content/uploads/2025/08/IJ-social-BlogFeatured-1280x720-2x-1.png https://blog.jetbrains.com/?post_type=platform&p=590419 The way developers create plugins implementing the Language Server Protocol (LSP) in JetBrains IDEs is undergoing a significant shift. With PyCharm and IntelliJ IDEA adopting a unified distribution model, we’re removing a key obstacle that has been limiting LSP adoption within the IntelliJ Platform ecosystem. Starting with IntelliJ IDEA Ultimate 2025.2, users can continue using a limited set of features, including the LSP API, even after their subscription expires. Community Edition (CE) will still be available in 2025.2 but will not include LSP support. See our other announcement to learn more.

Key changes in LSP availability

The most important update affects how LSP functionality is distributed in JetBrains IDEs:

Immediate impact (2025.2): The LSP API, which is already available to IntelliJ IDEA Ultimate users, will now be accessible for free within a limited feature set when their subscription expires. This change addresses long-standing feedback from plugin developers and smaller language communities, ensuring users no longer need to consider licensing restrictions when choosing between platforms.

Future changes (2025.3): With the new unified distribution, the traditional Community Edition will be sunset. All users will download a single IntelliJ IDEA installer, with IntelliJ IDEA Ultimate features requiring a subscription to be unlocked, but LSP support will remain available to everyone.

The LSP implementation itself stays closed-source and commercial, but we’ll keep it fully accessible for third-party plugins at no charge. This means plugin developers can now target a much broader user base without requiring their users to purchase the IntelliJ IDEA license.

What does this mean for plugin developers

This change addresses one of the most persistent complaints from the developer community. Previously, plugins using the LSP were essentially limited to IntelliJ IDEA Ultimate users, creating a significant barrier for:

  • Open-source plugin developers who wanted to provide LSP-based language support without restricting their user base.
  • Niche language communities, where requiring a paid subscription made adoption impractical, especially for small teams or individual contributors.
  • Educational environments, where managing different IDE editions added unnecessary complexity and friction.

The unified approach means plugin developers can now:

  • Build LSP-based plugins that work for users of all JetBrains IDEs.
  • Reduce the complexity of explaining installation requirements to users.
  • Compete more effectively with competitors’ extensions, which have had universal LSP support.

Current LSP capabilities and setup

The LSP API in the IntelliJ Platform has matured significantly since its introduction in 2023.2 and currently supports the following:

Core language features:

  • Code completion with resolve support
  • Go to definition and type definition
  • Hover documentation
  • Find references definition
  • Semantic highlighting
  • Diagnostics (both push and pull models)

Advanced features:

  • Code actions and quick-fixes
  • Document formatting
  • Document links and color preview
  • Intention actions
  • Workspace commands

Plugin developers should target IntelliJ IDEA Ultimate 2025.2.1+ and include the optional dependency on the com.intellij.modules.lsp module in the plugin.xml file.

<idea-plugin>
  <depends optional=”true” config-file="lsp.xml">com.intellij.modules.lsp</depends>
</idea-plugin>

To ensure the plugin is only available for installation in 2025.2.1+ and later, specify the since-build property in your build.gradle.kts file with:

intellijPlatform {
    pluginConfiguration {
        ideaVersion {
            sinceBuild = "252.25557"
        }
    }
}

If your project is based on the Plugin Template, set the relevant build number in the gradle.properties file:

pluginSinceBuild=252.25557
  1. To integrate the Kotlin LSP, two components are needed:
  2. An LSP server descriptor that specifies supported files and offers a command line to launch the server as a standalone process.
  3. An LSP support provider that ensures the server is accessible for a given file.

Server Descriptor

The following KotlinLspServerDescriptor creates an LSP support provider for the Language Server for Kotlin that handles Kotlin files (.kt extension). The provider will ensure that the language server runs in a separate process from the kotlin-lsp binary available in the PATH environment variable.

private class KotlinLspServerDescriptor(project: Project)
    : ProjectWideLspServerDescriptor(project, "KN Kotlin LSP") {

    override fun isSupportedFile(file: VirtualFile) =
        file.extension == "kt"

    override fun createCommandLine() =
        GeneralCommandLine("kotlin-lsp", "--stdio")
}

LSP Support Provider

Create an LSP support provider that initiates the LSP server when needed, using the appropriate server descriptor.

class KotlinLspServerSupportProvider : LspServerSupportProvider {

    override fun fileOpened(
        project: Project,
        file: VirtualFile,
        serverStarter: LspServerSupportProvider.LspServerStarter,
    ) {
        if (file.extension == "kt") {
            serverStarter.ensureServerStarted(
                KotlinLspServerDescriptor(project)
            )
        }
    }
}

The LSP support provider must be registered in the plugin descriptor, next to the main plugin.xml, within the existing lsp.xml file.

<idea-plugin>
  <extensions defaultExtensionNs="com.intellij">
    <platform.lsp.serverSupportProvider
      implementation="com.example.KotlinLspServerSupportProvider"/>
  </extensions>
</idea-plugin>

You can find the above LSP implementation as a Kotlin Notebook example here: https://github.com/Kotlin/kotlin-notebook-intellij-platform/blob/master/examples/lsp.ipynb

Trade-offs

The IntelliJ Platform documentation is clear about positioning: The LSP approach shouldn’t be considered as a replacement for the existing language API but rather as an added value. While LSP development offers significant advantages, such as reduced maintenance effort, faster development cycles, and cross-platform consistency, it is important to keep the following limitations in mind:

  • Limited IDE integration: The LSP approach provides less access to the IntelliJ Platform’s robust native features, which are deeply integrated via the Program Structure Interface (PSI).
  • Performance considerations: Using an LSP-based plugin introduces communication overhead compared to native implementations.
  • Feature parity gaps: Some advanced IDE features may not currently have LSP equivalents, limiting the scope for certain plugin developers.

The LSP serves as a practical, lightweight solution for plugin developers seeking to reduce complexity and expand their reach while delivering consistent language support. For those who need deeper integration with IntelliJ Platform features, native APIs like the PSI remain the preferred choice.

Getting started with LSP development

To explore LSP integration, plugin developers should:

  1. Review the comprehensive documentation available in the IntelliJ Platform Plugin SDK.
  2. Examine existing implementations like the open-source Prisma ORM plugin.
  3. Start with basic features and gradually add more sophisticated capabilities.
  4. Plan for the 2025.2 release to leverage universal LSP support.

Wrapping up and looking ahead

Removing commercial licensing for LSP integration on the IntelliJ Platform eliminates a significant problem for plugin developers, allowing them to prioritize efficiency and feature work.

More importantly, this shift represents more than a purely technical change; it underscores JetBrains’ recognition that language server development should be accessible to the broader developer community, not just those building commercial products.

While LSP integration won’t replace every native API, it provides a practical, lightweight solution for delivering consistent language support across all JetBrains IDEs. This fosters competition and presents an opportunity for plugin creators to target a broader audience. With the 2025.2 release, plugin authors can now evaluate and adopt the LSP on its technical merits, free from licensing constraints.

]]>
https://blog.jetbrains.com/zh-hans/platform/2025/09/the-lsp-api-is-now-available-to-all-intellij-idea-users-and-plugin-developers/
Kotlin Notebook Meets IntelliJ Platform: Advancing IDE Plugin Development https://blog.jetbrains.com/platform/2025/08/kotlin-notebook-meets-intellij-platform-advancing-ide-plugin-development/ Wed, 06 Aug 2025 10:32:10 +0000 https://blog.jetbrains.com/wp-content/uploads/2025/08/blogcover.jpg https://blog.jetbrains.com/?post_type=platform&p=589720 The value of extensibility

The ability to extend and customize software, from game mods to browser extensions, gives users a sense of freedom and the chance to bring their ideas to life. JetBrains IDEs already provide this sense of freedom through their support for plugins.

For some time now, creating plugins for JetBrains IDEs has been possible, but getting started with these sorts of projects can be intimidating. Navigating documentation, project templates, IntelliJ Platform dependencies, and Gradle configurations can be overwhelming for those wanting to experiment and test their ideas in real-world scenarios. Luckily, there’s now a more efficient option!

Introducing Kotlin Notebook

Kotlin Notebook is an interactive platform for data analysis, visualization, and prototyping with Kotlin. Like Jupyter Notebook, it provides a robust environment for data scientists, engineers, and researchers to explore and showcase their work within a dynamic, executable document. It combines Kotlin’s capabilities with the interactiveness of notebooks, allowing you to write and run code while seeing the results and visualizations in the same environment. This encourages an iterative workflow, boosting productivity and collaboration on data projects.

Building on the Kotlin Notebook plugin, we have started exploring how to connect it with the IntelliJ Platform. This enables the direct execution of IntelliJ Platform code from a notebook file within the active IDE runtime. The iterative workflow of Kotlin notebooks allows you to brainstorm, build, and test plugin features faster. The integration with the IntelliJ Platform makes moving the finished code into your plugin easy.

This initial idea has developed into a strong integration, and as of the 2025.2 release, the functionality is now available for use.

Getting started: A practical guide

To get started, create a new Kotlin notebook either as a new file in your project or as a scratch file, using ⌘⇧N on macOS or Ctrl+Shift+N on Windows/Linux.

Notebooks are based on the concept of cells. To start using this integration, switch to Run in IDE Process mode, create a new code cell, and declare:

%use intellij-platform

Due to the technical issues on Windows, it’s recommended to explicitly request the latest available version until the IntelliJ IDEA 2025.2.1 is released using:

%useLatestDescriptors
%use intellij-platform

Once you do this, the necessary IntelliJ Platform libraries will be loaded into the notebook’s classpaths, making them available for import in the subsequent cells.

Core features

UI rendering made simple

The ability to run code within the same IDE environment removes the need to build a full plugin project to test UI components. The runInEdt {} The helper ensures that the code runs on the Event Dispatch Thread (EDT), catching any exceptions and showing them below your cell.

Returning UI elements as a response when working with the Kotlin UI DSL or standard Swing components renders them immediately. All rendered components stay fully interactive.

Resource management with the Disposer

The integration uses the Disposer mechanism available in the IntelliJ Platform. A dedicated global notebookDisposable variable allows for registering and later disposing of specific notebook elements, such as extensions, listeners, actions, or UI components. This ensures the IDE manages the lifetime of your objects when you close the project or restart the notebook.

// Register something that needs cleanup
Disposer.register(notebookDisposable, myDisposable)

Disposer.register(notebookDisposable) {
  // Cleanup components directly
}

Loading plugins

When you integrate your notebook with the IntelliJ Platform, only the core platform is initially loaded into the classpath, similarly to when you’re working on a standalone plugin. However, you may need to depend on and use other plugins, whether bundled or installed from JetBrains Marketplace. To load plugins installed in your IDE, you must explicitly call the loadPlugins(vararg pluginIds: String) helper.

// Load specific plugins
loadPlugins("Git4Idea", "com.intellij.java")

Extension registration

In traditional plugin development, extensions are defined in the plugin.xml file. With Kotlin notebooks, you can dynamically register extensions using registerExtension(), avoiding the need for a structured plugin project.

For example, to register a custom ChatMessageHandler and ChatAgent for the AI Assistant plugin, you can simply run the following:

loadPlugins("com.intellij.ml.llm")
class MyChatMessageHandler : ChatMessageHandler {

    override fun isApplicable(project: Project, kind: ChatKind, userMessage: UserMessage) = true

    override fun createAnswerMessage(
        project: Project,
        chat: ChatSession,
        userMessage: UserMessage,
        kind: ChatKind,
    ) = SimpleCompletableMessage(chat)

    override suspend fun serveAnswerMessage(
        project: Project,
        chat: ChatSession,
        answerMessage: ChatMessage,
        smartChatEndpoints: List<SmartChatEndpoint>,
    ) {
        ChatAgent.EP_NAME.extensionList
            .find { it.id == "groot" }
            ?.serveAnswerMessage(project, chat, answerMessage)
    }
}

registerExtension(ChatMessageHandler.EP, MyChatMessageHandler())
class MyChatAgent : ChatAgent {

    override val id = "groot"
    override val name = "I am Groot"

    override fun createAnswerMessage(
        project: Project,
        chat: ChatSession,
        userMessage: UserMessage,
        kind: ChatKind,
    ) = SimpleCompletableMessage(chat)

    override suspend fun serveAnswerMessage(
        project: Project,
        chat: ChatSession,
        answerMessage: ChatMessage,
    ) {
        answerMessage as SimpleCompletableMessage
        answerMessage.appendText("*I am Groot*".privacyConst)
    }
}

registerExtension(ChatAgent.EP_NAME, MyChatAgent())

Similarly, you can register a custom UI theme as follows:

import com.intellij.ide.ui.UIThemeProvider

val theme = UIThemeProvider().apply { 
    id = "My Theme"
    path = "Theme.json"
}
registerExtension(UIThemeProvider.EP_NAME, theme)

This approach allows you to experiment and test extensions instantly within the IDE runtime, streamlining development and saving time.

Exploring your IDE environment

The integration provides several ways to access the internal details of the currently running IDE, such as its build details and location in the file system. Exposed mechanisms such as the Plugin Manager and Plugin Repository allow for interacting with plugins available in JetBrains Marketplace, or even ones installed locally. All available variables and helper methods are documented in the relevant section in the IntelliJ Platform SDK documentation.

// Access IDE information
productInfo.name        // "IntelliJ IDEA"
productInfo.version     // "2025.3"
productInfo.buildNumber // "253.xxxx"

idePath // “/Users/hsz/Applications/IntelliJ IDEA Ultimate 2025.3 Nightly.app/Contents”

ide // com.jetbrains.plugin.structure.ide.Ide instance

// Work with the plugin manager
pluginManager.findEnabledPlugin(PluginId.getId("com.intellij.java"))

// Request JetBrains Marketplace
pluginRepository.pluginManager.searchCompatibleUpdates(
    build = "${productInfo.productCode}-${productInfo.buildNumber}",
    xmlIds = listOf(“org.jetbrains.junie”),
    channel = “default”,
)

Opportunities and improvements

Integrating Kotlin Notebook with the IntelliJ Platform represents a significant step forward for custom plugin development. With traditional barriers associated with project setup, compilation, and deployment removed, developers can now concentrate more effectively on implementing their ideas.

We already have great ideas for ways to improve this experience further:

  • Rapid prototyping of IDE features and plugins: This functionality allows for the development of features, with the potential for AI assistance in the refinement process. Once you’ve completed a scratch implementation of your plugin in your notebook file and it is ready to be adapted for use in a Plugin Template-based project, you can use Junie to convert it and give it a formal plugin structure.
  • Expeditious testing of platform APIs and behaviors: The JetBrains QA teams are already using Kotlin notebooks to debug the IntelliJ Platform more quickly, achieving particular success when using them with a UI testing framework. Improving scripting and adding reusable helpers can make notebooks more adaptable and suited to this use case.
  • Interactive documentation and tutorials for IntelliJ Platform development: The storytelling style of notebooks, combining runnable code snippets with explanatory comments, can create a more engaging learning experience.
  • Compose/Jewel support: As development advances in this area, the ability to render Compose/Jewel components is a natural next step, mirroring the current functionality supplied by Java Swing or the Kotlin UI DSL. This can be especially useful for prototyping IDE-specific UI/UX elements, whether you’re developing plugins or working on an entire IDE based on the IntelliJ Platform.

Take it for a spin and let us know what you think!

Follow these simple steps to get started:

  1. Create a new Kotlin Notebook.
  2. Switch to Run in IDE Process mode.
  3. Unleash your creativity with %use intellij-platform.

If you’d like to share feedback, please visit the JetBrains Platform forum, where we can discuss any challenges and ideas for improving this integration. You can also join the #notebooks public Slack channel for discussions and questions.

The IntelliJ Platform integration and the examples featured in this article are now publicly accessible on GitHub, along with a dedicated section in the IntelliJ Platform SDK documentation. We welcome pull requests with ideas to improve the user experience.

Happy hacking!
Jakub

]]>
Introducing TeamCity Recipes: Reusable CI/CD Building Blocks https://blog.jetbrains.com/teamcity/2025/07/introducing-teamcity-recipes/ Thu, 31 Jul 2025 12:23:21 +0000 https://blog.jetbrains.com/wp-content/uploads/2025/07/introducing-teamcity-recipes-featured.png https://blog.jetbrains.com/?post_type=teamcity&p=587748 Build steps are often repeated over and over – within a single project or team, or even across a whole organization. These patterns tend to get copy-pasted, manually adapted, and maintained in parallel. This can lead to inconsistencies and extra maintenance work.

With the latest TeamCity release, we’re addressing that problem head-on. Say hello to TeamCity recipes: customizable build steps that can be reused, versioned, and published on the JetBrains Marketplace (or used internally in your organization).

Whether you’re managing dozens of pipelines or just want to save time setting up repeatable build logic, recipes are designed to streamline your CI/CD workflows. Let’s take a closer look at what recipes are about.

What are TeamCity recipes?

Recipes are build steps you can save and reuse whenever you need to repeat the same setup. They help you avoid reinventing the wheel by letting you define and reuse common build logic.

TeamCity recipes on JetBrains Marketplace

Recipes can be:

Each recipe can include configurable parameters, documentation, and versioning, making them easy to integrate and maintain.

For more information about what recipes are and how they’re different from meta runners, please refer to our documentation.

What’s new in this release?

Public contributions via the JetBrains Marketplace

For the first time, external users can publish their own recipes to the JetBrains Marketplace. This opens the door to a community-driven ecosystem of reusable build logic, maintained and shared by TeamCity users around the world.

To upload your own recipes to the Marketplace, follow these steps.

Redesigned recipe installation UI

Our new interface provides a more user-friendly installation experience:

  • View author details and recipe versions.
  • Install specific versions.
  • Preview source code before installing.
Example of a TeamCity recipe

This transparency ensures that users can review and trust third-party contributions.

YAML support for private recipes

Previously known as meta runners, private recipes can now be written in YAML. This modern syntax improves readability and maintainability. While XML is still supported for backward compatibility, YAML is now the recommended format.

Unified UI for recipe management

Manage both public and private recipes from a single interface:

  • Upload and organize private recipes at the project level.
  • View usage across build configurations and templates (including private recipes).
  • Detect outdated or unavailable recipes that could break builds.

Why use TeamCity recipes?

Whether you’re reusing steps within your organization or using recipes created within your organization or outside of it, this feature offers a practical way to reduce duplication and simplify maintenance.

Public recipes give you access to a growing library of build steps created by the TeamCity community. Because each recipe is a small, self-contained file with visible source code, you can review what it does before using it. 

Private recipes, on the other hand, help teams standardize their internal workflows. Written in YAML, they’re easier to read, edit, and debug compared to older XML-based meta runners. And because they’re scoped to your TeamCity project or organization, they stay private and secure.

Both public and private recipes are easier to create and share than full-fledged plugins, lowering the barrier to contribution.

Built for safety

The idea behind recipes might feel familiar: many CI tools offer reusable build logic. But with TeamCity Recipes, we’ve taken a more opinionated approach to how they’re configured, shared, and executed, focusing strongly on security, transparency, and ease of use.

Unlike some other ecosystems, TeamCity doesn’t default to using floating versions like latest, which can introduce unintentional changes into your builds. When you install a recipe, you choose a specific version, giving you more control and predictability.

When a new version becomes available, TeamCity will notify you, but won’t auto-upgrade anything without your knowledge and permission.

Every public recipe comes with visible source code you can inspect directly from the TeamCity UI before installing and from the overview page after the installation. Once installed, the build step editor automatically adapts to the Recipe’s parameters, presenting clear controls and descriptions instead of relying on manual text input. 

This makes Recipes not only easier to trust, but also easier to configure and debug, especially for teams that value visibility and safety.

How to publish a recipe

Publishing a recipe is simple:

  1. Log in to the JetBrains Marketplace.
  2. Choose “TeamCity Recipes” as the plugin type.
  3. Upload your recipe with metadata and namespace (to avoid naming collisions). Namespaces allow multiple users to publish recipes with the same name under different scopes.

Please also refer to our documentation for more information on how to upload a new recipe.

Give it a try

Recipes are now live in TeamCity. Browse the Marketplace, experiment with public recipes, or create your own to simplify and supercharge your CI/CD pipelines.

We believe this feature will help foster a more vibrant, collaborative TeamCity community, and we can’t wait to see what you build 🚀

Stay tuned for upcoming tutorials and videos showcasing what’s possible with recipes!

]]>
Bringing Remote Closer to Local: 2025.2 Highlights https://blog.jetbrains.com/platform/2025/07/bringing-remote-closer-to-local-2025-2-highlights/ Mon, 28 Jul 2025 10:48:56 +0000 https://blog.jetbrains.com/wp-content/uploads/2025/07/RemDev2025.2.png https://blog.jetbrains.com/?post_type=platform&p=585366 Our goal is to make remote development with JetBrains IDEs feel just as reliable and consistent as working locally does. Recently, we’ve made progress towards this goal in core areas like the editor, tool windows, plugin behavior, and settings synchronization. 

Editor

All the changes made to the editor in the 2025.2 release are based on a single underlying idea: to make remote editing feel as seamless and responsive as working locally.

We improved the way the editor opens in remote sessions. To reduce the perceived delay between user action and UI feedback, we’ve changed how fast different UI elements appear when opening a file. Now, when a file is opened in a remote session, the editor tab appears immediately, first with the tab frame and file name, followed by the file content as soon as it’s available.

We’re also experimenting with a skeleton view for cases where the editor content cannot be displayed fast enough, with the goal of making the UI feel more responsive. Once the data arrives, the skeleton is seamlessly replaced by the actual file content. Please share your feedback on this change!

To improve responsiveness, we’ve moved several basic editor actions to the frontend:

  • The clipboard now reliably captures the correct selection when copy-pasting, even when actions happen quickly.
  • Identifier highlighting under the caret now feels faster thanks to frontend caching. The first time something is highlighted, it’s calculated on the backend, but repeated highlights appear instantly while the file stays open.

Using the Java plugin as an example, we’ve made progress toward smarter frontend execution by moving more functionality to the frontend. This includes:

  • Code selection and navigation (brace matching and word selection).
  • Statement and element movement (up/down and left/right).
  • Code formatting and indentation.
  • Smart Enter processing.
  • Simple highlighting.

Thanks to these changes, the caret now moves much more predictably, even after smart backend updates are applied.

We’ve also extended this approach to SQL, JSON, YAML, TOML, and Ruby, which are now all available in the released version.

There is more work ongoing for upcoming releases, including native-feeling remote development support for other programming languages.

Debugger

We’ve started rolling out a split frontend/backend architecture for the debugger. One of the biggest advantages is that the debugger is less coupled with the network delay. For instance, if you place or delete a breakpoint, it will be applied immediately, with a subsequent interaction with the backend. We’ve also added support for core debugging features like frames, variables, watches, and more, and we’re continuing to work on developing additional features. 

While not all functionality is in place yet, the current implementation is fully usable, and the missing features don’t block core debugging workflows.

Terminal

The initial implementation of the split terminal was written between 2024.3 and 2025.1. We finally enabled it by default in 2025.2. The new release fixed many issues related to the previous version of the terminal, and the change was highly anticipated by many individual and corporate customers.

These updates improve the current experience and lay the foundation for future enhancements, ensuring new features will now work natively in remote development mode.

Platform functional windows

Popups with long or dynamic lists have historically performed poorly in remote development scenarios, especially over unstable or high-latency connections. The redesigned versions now provide the same native-level performance when working remotely as they do when working locally, offering smooth scrolling and instant selection, even on slower or less reliable networks.

  • Search Everywhere: The most used features are now fully supported, and the popup performs smoothly in remote development scenarios.
  • Find in Files: This popup now feels fast and responsive, and several long-standing issues have been resolved.
  • Git Branch widget: We’ve improved this widget’s performance and responsiveness under high latency.

Plugin experience

With the latest release, we introduced synchronization of plugins between the client and the host. The IDE now installs the necessary plugins on the client machine based on the host’s setup and vice versa. This allows the development environment to remain consistent with minimal user involvement. The synchronization behavior can be configured depending on the security requirements in specific companies.

IDE settings

We fixed an issue where various project settings were lost between IDE restarts. Recent updates make sure that selected UI and project-specific settings are preserved so that you can resume work exactly where you left off.

Here’s what now persists correctly:

  • IDE window size and position.
  • Layout and state of tool windows.
  • Open files and their order.
  • Tool window-specific settings, such as appearance and behavior in the Project view.

Toolbox and remote development

Remote development support in Toolbox was released in April, and while there’s still room for improvement, early feedback has been very positive. Several companies have confirmed that using Toolbox significantly improves connection stability.

In synthetic tests, we observed connection performance improvements of 1.5x or more:

In addition to performance gains, Toolbox supports OpenSSH, works with any major remote host’s OS (not just Linux, but Windows and macOS, too), and lets you manage everything from setup to updates in the same way you handle your IDEs locally. This results in a smoother remote workflow that’s built for how you actually work. You can read more about remote development with Toolbox in our recent blog post.

We’ve also added a new feature: If Toolbox is running, you can now see remote projects in the Recent Projects popup, right alongside your local projects.

Other important improvements

This year, we focused on improving core functionality – frequently used windows, actions, and better separation of components and languages between the frontend and backend. Our goal is to build a unified architecture that works consistently in both monolith and remote development environments.

That said, there are still some tricky parts of the IDE stack to tackle, like syncing keymaps, color schemes, and other settings.

We’ve also fixed several bugs. Here are some of the most important ones:

]]>
The Reworked Terminal Becomes the Default in 2025.2 https://blog.jetbrains.com/platform/2025/07/the-reworked-terminal-becomes-the-default-in-2025-2/ Fri, 18 Jul 2025 12:23:37 +0000 https://blog.jetbrains.com/wp-content/uploads/2025/07/IDEs-social-BlogFeatured-1280x720-2x.png https://blog.jetbrains.com/?post_type=platform&p=584176 Starting from 2025.2, the default terminal implementation is now the reworked terminal. To create this new implementation, the classic terminal was rewritten almost from scratch to provide the technical foundation for new terminal features like visual separation of executed commands, AI integration, and the ability to work seamlessly in remote development scenarios.

Functionally, it is still the same terminal, but it comes with some novel visual additions.

Separators between executed commands (Bash and Zsh)

Screenshot 2025-07-01 at 10.03.27.png

We’ve added separators between executed commands to make it easier to distinguish where commands start and end.

If you wish to hide these separators, you can do so by going to Settings | Tools | Terminal and disabling the Show separators between executed commands option.

For now, this feature is only available when running Bash or Zsh, but we plan to implement it for PowerShell in the next release. You can follow this YouTrack issue for updates.

Updated color scheme

We have updated the color schemes in both light and dark themes to improve the readability of command outputs and alternate buffer app renderings.

Screenshot 2025-07-01 at 10.40.35.png

If necessary, you can customize these color schemes in Settings | Editor | Color scheme | Console colors | Reworked terminal. If you experience any specific color issues, we encourage you to report these on IJPL-187347.

Performance 

Improving performance was one of our main goals, and the reworked terminal is now several times more performant on fast command outputs than the classic terminal.

Remote development 

The reworked terminal was built considering the architectural requirements necessary to provide the same user experience and quality in both local and remote development.

Classic terminal still available for backward compatibility

We tried our best to achieve feature parity with the classic implementation, but if some scenarios are not covered in the reworked terminal, you can switch to the classic terminal via the Terminal engine option in Settings | Tools | Terminal.

There are many internal and external dependencies on the Classic Terminal API, so it will remain available for at least two more releases to ensure a smooth transition both for users and plugin writers.

Some functionalities in third-party plugins that rely on the classic terminal implementation might be limited in 2025.2. This might affect plugins that get text from, execute commands in, and add custom key bindings to the classic terminal. We already informed plugin vendors about API changes and published some technical details in the platform community forum.

A work in progress 

We’re still working on further terminal improvements and would be grateful for your input.

If you have any feedback, feel free to submit it either from the IDE by clicking Share your feedback in the three-dot menu in the Terminal tool window or by submitting a new ticket to our bug tracker. 

]]>
Busy Plugin Developers Newsletter – Q2 2025 https://blog.jetbrains.com/platform/2025/07/busy-plugin-developers-newsletter-q2-2025/ Tue, 08 Jul 2025 16:13:19 +0000 https://blog.jetbrains.com/wp-content/uploads/2025/07/Screenshot-2025-07-08-at-18.06.51.png https://blog.jetbrains.com/?post_type=platform&p=579513 ⭐️ Community highlights

Speak at JetBrains Plugin Developer Conf 2025 – Submit a Talk

Plugin Developer Conf returns on November 5, 2025, and we’re looking for speakers to join the lineup! This free, one-day online event brings together the JetBrains plugin developer community to share insights on building and managing plugins.
Last year’s online conference welcomed over 2,500 online attendees and featured sessions from eleven expert speakers. If you have lessons, tips, or stories about plugin development, maintenance, or overcoming challenges, submit your talk proposal by July 15, 2025.

Learn more and apply in this blog post.

⭐️ Marketplace updates

Trader Verification Requirement on JetBrains Marketplace

To comply with the Omnibus Directive and Digital Services Act, JetBrains Marketplace requires vendors who identify as traders to provide additional verification details. This includes contact information, identification documents, and banking details. Vendors who haven’t completed this process may face suspension.
Read the full blog post to ensure you’re meeting the latest requirements.

JetBrains Marketplace Reflects PyCharm Changes

With the release of PyCharm 2025.1, PyCharm is now a single, unified product offering core features for free and a Pro subscription for advanced tools. In response to this change, JetBrains Marketplace has updated the way PyCharm category is displayed: the “PyCharm Community” has been removed from product filters and dropdowns, and “PyCharm Professional” has been renamed to “PyCharm.” Plugin compatibility labels have also been revised to clearly distinguish between plugins compatible with the full PyCharm IDE and those specific to the Community edition.

⭐️ Plugin development tooling updates

IntelliJ Plugin Verifier 1.388

The IntelliJ Plugin Verifier checks binary compatibility between IntelliJ-based IDE builds and plugins. Version 1.388 introduces several structural improvements and new features, including better handling of content module dependencies, support for Fleet products that follow IntelliJ versioning, and enhanced TeamCity recipe functionality. It also includes updates to ByteBuddy and Gradle, and fixes an issue with missing plugin-declared dependencies.

Check out the changelog for full details.

IntelliJ Platform Gradle Plugin 2.6.0

The IntelliJ Platform Gradle Plugin is a plugin for the Gradle build system to help configure your environment for building, testing, verifying, and publishing plugins for IntelliJ-based IDEs. 

Version 2.6.0 brings new helper methods to simplify resolving plugin dependencies from JetBrains Marketplace, adds support for CSS and XML test frameworks, and improves task output and warnings for Plugin Verifier runs. It also deprecates Aqua (QA) as a target platform and includes a range of internal fixes and dependency resolution improvements.

You can find the full changelog here.

⭐️ Useful resources

Livestream Recording: Plugin Verifier and API Compatibility Maintenance

In a recent session, IntelliJ Platform Developer Advocate Róbert Novotný walked through the Plugin Verifier, one of the most important tools for maintaining plugin compatibility across JetBrains IDEs. The session focused on spotting breaking API changes, avoiding internal APIs, and verifying plugin behavior across IDE versions.

Watch the recording or check out the key takeaways in our blog post.

Integration Tests Blog Series: GitHub Actions and Setting Up Continuous Integration

Following the enthusiastic response to our Plugin Testing: Performance, UI, and Functional Testing session at JetBrains Plugin Developer Conf 2024, we launched a blog series that takes a deeper dive into plugin testing strategies. The fourth installment shows how to automate your integration tests using GitHub Actions, helping you catch issues early and run tests across different environments.

New Project Wizard API

This new article provides a comprehensive overview of the New Project Wizard API in the IntelliJ Platform, which powers project and module creation dialogs. It explains the architecture behind language and framework project generators, how to build and chain wizard steps, manage shared data, and create responsive UIs with property graphs. The guide also covers advanced features like branching logic, persistent defaults, and support for custom build systems — offering practical insights for anyone implementing project wizards.

]]>
Testing a Fresh Look for JetBrains IDEs https://blog.jetbrains.com/platform/2025/06/testing-a-fresh-look-for-jetbrains-ides/ Thu, 19 Jun 2025 10:11:27 +0000 https://blog.jetbrains.com/wp-content/uploads/2025/06/Testing-a-fresh-look-for-JetBrains-IDEs.png https://blog.jetbrains.com/?post_type=platform&p=575832

Visual context is always changing – and so should the look and feel of the tools you use every day. We know how much a familiar UI matters, and we’ve heard your feedback from past updates. That’s why we’re taking an iterative, careful approach this time: small, focused improvements, shared early, with your feedback guiding what comes next.

In the latest 2025.2 EAP of JetBrains IDEs, you can find two new UI styles: One Island and Many Islands, each available with both dark and light modes. Ultimately, one of these styles will become the new default – your feedback will help us decide which one.

This update is purely visual – all functionality remains unchanged. You can switch between the new styles and your previous theme at any time.

Why the new themes?

With this update, we aim to achieve several goals:

  • Stay current: We want our UI to feel fresh and modern, keeping pace with evolving design trends. While the last UI overhaul was introduced a couple of years ago, its foundations were laid over five years ago. This time, we’re focusing purely on visual refinements, with minimal changes to update the look.
  • Refine the previous UI update: We’re improving areas where the design can be clearer or more effective, such as the separation between the editor and tool windows, more prominent navigation, and better tab visibility.
  • Align with our broader design language: We aim to bring the JetBrains IDEs closer in line with the design of our other products, such as Toolbox and Fleet, for a more consistent experience across the JetBrains ecosystem.

One Island style

Many Islands style

We need your help

We invite you to try the new styles and share your thoughts. After using a new theme for a while, you’ll get a prompt to fill out a short survey that shouldn’t take more than five minutes to complete. Your feedback will help us decide which style to finalize and roll out as the default.

Known issues

We’re already working on some known issues. Please vote and comment on them, or submit a new issue if you notice something we haven’t already been made aware of.

]]>
https://blog.jetbrains.com/zh-hans/platform/2025/06/testing-a-fresh-look-for-jetbrains-ides/
JetBrains Plugin Developer Conf 2025 – Call for Speakers https://blog.jetbrains.com/platform/2025/06/jetbrains-plugin-developer-conf-2025-call-for-speakers/ Tue, 17 Jun 2025 15:32:37 +0000 https://blog.jetbrains.com/wp-content/uploads/2025/06/MP-social-BlogFeatured-1280x720-2x.png https://blog.jetbrains.com/?post_type=platform&p=575781 Plugin Developer Conf is back this November! We’re looking for speakers to share their insights with the JetBrains plugin developer community. Submit your talk by July 15, 2025.

What is JetBrains Plugin Developer Conf?

Plugin Developer Conf is a free, live, online event hosted by JetBrains, created for and shaped by the plugin development community. It’s a one-day virtual gathering focused on all aspects of building and managing plugins for JetBrains products.

The first-ever Plugin Developer Conf took place last year, bringing together over 2,500 online attendees and featuring sessions from eleven experienced speakers who shared practical insights on plugin testing, localization, user feedback, and more.

This year, we’re gathering the community once again to exchange ideas, lessons, and strategies for building better plugins. On November 5, 2025, we’ll host the next edition of the conference, and we’re currently putting together the agenda.

We’re now looking for speakers! Whether your talk covers building and maintaining plugins, overcoming challenges, or sharing best practices — we’d love to hear from you. Your experience could help fellow plugin authors on their journey.

What type of talks are we looking for?

You’re welcome to submit any talk related to plugin development or JetBrains Marketplace, but here are a few topics we’re especially interested in:

  • Finding a plugin idea
  • Developing a plugin
  • Navigating the approval process with the Marketplace team
  • Marketing and monetizing a plugin
  • Managing user feedback and support
  • Maintaining plugin compatibility and handling technical issues
  • Overcoming any challenges you may have encountered on Marketplace
  • Best practices for aspiring plugin developers
  • Anything that does not fit the list above but is related to plugin development and management

To give you an idea, here are some talks from 2024:

  • Experiences building a Language Server Protocol plugin
  • Be kind and localize! Implementing localization in JetBrains plugins
  • Handling user feedback: A case study with GitHub Actions Manager

What’s the format for talks?

All talks will be presented live in English and can run for 30 or 45 minutes, followed by an optional 5–10 minute Q&A. We’ll schedule your session during business hours in your time zone and are happy to support you with dry runs, demo feedback, and presentation prep if needed.

Talks will be streamed and recorded, then shared on JetBrains YouTube, newsletters, blogs, and other official channels. You’re welcome to use a slideshow, live demo, or any format that best suits your content.

As a thank-you, selected speakers will receive a 1-year personal JetBrains All Products Pack and, if you’d like, we’ll also help promote your blog, project, or course alongside your talk.

The Call for Speakers will remain open until July 15, 2025.

Not sure if your talk idea will fit? Reach out to elena.kerpeleva@jetbrains.com and we can discuss!

Excited to hear your stories — submit your talk today!

]]>
Plugin Verifier and API Compatibility Maintenance: Livestream Recording & Key Takeaways https://blog.jetbrains.com/platform/2025/05/plugin-verifier-and-api-compatibility-maintenance-livestream-recording-amp-key-takeaways/ Fri, 30 May 2025 13:34:43 +0000 https://blog.jetbrains.com/wp-content/uploads/2025/05/Featured_Blog_1280x720-5-2.png https://blog.jetbrains.com/?post_type=platform&p=570963 In a recent session, IntelliJ Platform Developer Advocate Róbert Novotný walked through the Plugin Verifier—one of the most important tools for maintaining plugin compatibility across JetBrains IDEs. The session focused on spotting breaking API changes, avoiding internal APIs, and verifying plugin behavior across IDE versions.

If you couldn’t join us live, the full recording is now available on JetBrains TV.

And if you prefer reading over watching, this blog post sums up the key takeaways from the session.

What is the IntelliJ Plugin Verifier?

The IntelliJ Plugin Verifier is a tool that ensures a plugin behaves correctly across JetBrains IDE versions. It checks for compatibility issues with the evolving IntelliJ Platform APIs, and validates that a plugin:

  • Contains a complete and correct plugin descriptor (plugin.xml)
  • Uses APIs that are available and compatible with target IDE versions
  • Avoids deprecated, internal, or experimental APIs

JetBrains Marketplace relies on the Plugin Verifier to assess plugins upon upload, acting as a quality gate for all listed plugins.

Why Compatibility Matters

Publishing a plugin to JetBrains Marketplace is about more than just passing basic validation. End users expect plugins to work reliably, without errors or unexpected behavior. The Plugin Verifier helps plugin authors ensure their plugins will run smoothly across IDE versions, minimizing user disruption.

Typical Compatibility Challenges

The session covered several types of issues that the Plugin Verifier can detect:

  • Deprecated APIs: These may work now but are scheduled for removal in future platform versions.
  • Internal APIs: Not intended for external use, these may change without notice and break plugins.
  • Experimental APIs: Unstable and subject to change, their use is discouraged.
  • Override-only APIs: These should only be overridden, not invoked directly.
  • Visibility changes: Classes, methods and fields may become protected or public.
  • Structural changes: Classes may become interfaces or vice versa, breaking assumptions in plugin code.

Example: Plugin verification results

Running the Plugin Verifier Locally

To avoid the delay of uploading a plugin just to see it fail verification, developers can and should run the Plugin Verifier locally. There are two main ways to do this:

  1. With IntelliJ Platform Gradle Plugin: This is the recommended approach. The Gradle plugin provides tasks like verifyPlugin and verifyPluginStructure for integrated verification.
  2. Standalone Tool: Developers can download the Plugin Verifier JAR from GitHub or Maven Central and run it via the command line.

The session also walked through how to set up both methods, showing how developers can validate plugins against multiple IDE versions, identify API compatibility problems, and fix issues before publication.

Integrating with CI/CD

Integrating the Plugin Verifier into a continuous integration pipeline saves time and prevents issues from reaching production. The verifier can be run against new plugin versions and upcoming IDE releases to catch problems proactively.

Handling Warnings and Errors

While the Plugin Verifier highlights potential problems, not all warnings are show-stoppers. Some rules (like those about naming or older plugin IDs) can be muted locally using CLI flags (e.g., --mute). However, JetBrains Marketplace may enforce stricter rules, and muted issues locally do not affect Marketplace verification.

Best Practices

To get the most out of the Plugin Verifier and to avoid common pitfalls later on, keep these practical tips in mind:

  • Avoid internal and deprecated APIs whenever possible.
  • Use stable and documented APIs that are part of the official SDK.
  • Run verification locally before every release.
  • Regularly check compatibility against newer IDE versions.

Resources and Further Reading

Conclusion

The Plugin Verifier is a crucial tool in the JetBrains plugin development workflow. Whether integrated via Gradle or run standalone, it empowers developers to ship robust, future-proof plugins. By embracing it early in the development process, plugin authors can ensure a smoother path to publication and better experiences for their users.

]]>