Hi,
I have some issue with handling project-level PersistentStateComponents in split mode.
Currently, I have two modules for implementing the settings, settings-shared and settings-frontend with descriptors and classes like below.
When I first open the plugin’s settings UI, the checkbox states are set correctly according to the default state values.
- When I change them the first time (from default state to non-default), the corresponding settings XML is created in the project’s
.ideafolder with the correct, up-to-date state. - The opposite is true too, that when the settings change from non-default to default, the settings XML gets deleted from the
.ideafolder.
However, when I change the settings from a non-default state to another non-default state, the settings XML doesn’t get updated at all with the new state, only the UI part.
I’m kind of clueless as to what I might be missing.
- I have the
<projectSettings>and<rdct.remoteSettingProvider>registered for syncing the settings, which is working to a certain extent because the settings XML gets created and removed in the mentioned cases. - I tried switching from light service to
<projectService>registration. No difference. - I tried having the
rdct.remoteSettingProviderin the settings-shared module only, or in settings-frontend and a backend module that uses the settings, but that didn’t make any difference. - I also tried using
Direction.InitialFromFrontendinstead ofDirection.InitialFromBackend, just in case. No difference. - I even tried with a minimal project setup that contains only the settings-shared and settings-frontend modules to see if anything else interferes with it. No difference.
Has anyone else encountered this issue before?
Environment
I could reproduce it in a split-mode sandbox IDE and in a VirtualBox (as remote) + JetBrains Gateway setup where I install the plugin via the Install plugin from disk options.
I build on IJ 2026.2 with platform plugin 2.18.1.
Plugin configuration
settings-shared.xml
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<projectSettings service="settings.MySettings"/>
<rdct.remoteSettingProvider
implementation="settings.MySettingsRemoteInfoProvider"/>
</extensions>
</idea-plugin>
settings-frontend.xml
<idea-plugin>
<dependencies>
<module name="intellij.platform.frontend"/>
<module name="settings-shared"/>
</dependencies>
<resource-bundle>messages.MySettingsBundle</resource-bundle>
<extensions defaultExtensionNs="com.intellij">
<projectConfigurable id="MyConfigurable"
instance="settings.MyConfigurable"
groupId="tools"
key="my.configurable"/>
</extensions>
</idea-plugin>
PersistentStateComponent
@State(name = "MySettings", storages = [Storage(value = "mySettings.xml")])
@Service(Service.Level.PROJECT)
class MySettings(private val project: Project) : PersistentStateComponent<MyState> {
var isFirstOption: Boolean
get() = state.isFirstOption
set(value) { state.isFirstOption = value }
var isSecondOption: Boolean
get() = state.isSecondOption
set(value) { state.isSecondOption = value }
override fun noStateLoaded() {
loadState(MyState())
}
}
class MyState {
var isFirstOption: Boolean = true
var isSecondOption: Boolean = false
}
RemoteSettingInfoProvider
class MySettingsRemoteInfoProvider : RemoteSettingInfoProvider {
override fun getRemoteSettingsInfo() = mapOf(
"MySettings" to RemoteSettingInfo(direction = RemoteSettingInfo.Direction.InitialFromBackend)
)
}
Configurable
internal class MyConfigurable(private val project: Project) : Configurable {
//...
override fun createComponent(): JComponent {
val settings = project.service<MySettings>()
panel = panel {
row {
checkBox("First option").bindSelected(settings::isFirstOption)
}
row {
checkBox("Second option").bindSelected(settings::isSecondOption)
}
}
return panel
}
}