Repository: intellij-rust/intellij-rust
Issue: Rustfmt setting unsets External Linters setting

## Environment

* **IntelliJ Rust plugin version:** 0.4.164.4409-213
* **Rust toolchain version:** 1.58.1 (db9d1b20b 2022-01-20) x86_64-unknown-linux-gnu
* **IDE name and version:** IntelliJ IDEA 2022.1 EAP Ultimate Edition (IU-221.4165.146)
* **Operating system:** Linux 5.13.0-28-generic
* **Macro expansion engine:** new
* **Name resolution engine:** new

## Problem description

When starting a new project, the indicator on the bottom of the screen shows Cargo Check. Clicking it and updating the settings sometimes doesn't result in the settings being applied properly.

## Steps to reproduce

1. `cargo new anything`
2. Open the project in IntelliJ with the plugin installed
3. Click the Cargo Check indicator on the bottom of the page
4. Note that the indicator still shows `Cargo Check`
5. Change to `Clippy`
6. Click `Run external linter to analyze code on the fly`
7. Click `Apply`
8. Note that the indicator shows `Clippy`
9. Click on `Rustfmt`
10. Check `Use rustfmt instead of built-in formatter`
11. Click `Apply`
12. Note that the indicator shows `Cargo Check`


Changed files:
src/main/kotlin/org/rust/cargo/project/configurable/RsConfigurableBase.kt

diff --git a/src/main/kotlin/org/rust/cargo/project/configurable/RsConfigurableBase.kt b/src/main/kotlin/org/rust/cargo/project/configurable/RsConfigurableBase.kt
index 75be1af9f..3cbe60417 100644
--- a/src/main/kotlin/org/rust/cargo/project/configurable/RsConfigurableBase.kt
+++ b/src/main/kotlin/org/rust/cargo/project/configurable/RsConfigurableBase.kt
@@ -10,16 +10,18 @@ import com.intellij.openapi.options.ConfigurationException
 import com.intellij.openapi.project.Project
 import com.intellij.openapi.util.NlsContexts.ConfigurableName
 import com.intellij.util.PlatformUtils
-import org.rust.cargo.project.settings.RustProjectSettingsService
+import org.rust.cargo.project.settings.RustProjectSettingsService.State
 import org.rust.cargo.project.settings.rustSettings
+import kotlin.reflect.KMutableProperty1
+import kotlin.reflect.full.declaredMemberProperties
 
 @Suppress("UnstableApiUsage")
 abstract class RsConfigurableBase(
     protected val project: Project,
     @ConfigurableName displayName: String
 ) : BoundConfigurable(displayName) {
-
-    protected val state: RustProjectSettingsService.State = project.rustSettings.settingsState
+    protected val state: State = project.rustSettings.settingsState
+    private val oldState: State = state.copy()
 
     // Currently, we have help page only for CLion
     override fun getHelpTopic(): String? = if (PlatformUtils.isCLion()) "rustsupport" else null
@@ -28,9 +30,29 @@ abstract class RsConfigurableBase(
     final override fun apply() {
         super.apply()
         doApply()
-        project.rustSettings.settingsState = state
+        project.rustSettings.settingsState = getUpdatedState()
+    }
+
+    private fun getUpdatedState(): State {
+        val currentState = project.rustSettings.settingsState
+        for (property in stateProperties) {
+            val newValue = property.get(state)
+            val oldValue = property.get(oldState)
+            if (newValue != oldValue) {
+                property.set(currentState, newValue)
+            }
+        }
+        return currentState
     }
 
     @Throws(ConfigurationException::class)
-    protected open fun doApply() {}
+    protected open fun doApply() {
+    }
+
+    companion object {
+        @Suppress("UNCHECKED_CAST")
+        private val stateProperties = State::class.declaredMemberProperties
+            .filterIsInstance<KMutableProperty1<State, *>>()
+            as List<KMutableProperty1<State, Any?>>
+    }
 }