Repository: intellij-rust/intellij-rust
Issue: Format-on-save fails with rustup error: "Found argument '--installed' which wasn't expected, or isn't valid in this context"

## Environment

* **IntelliJ Rust plugin version:** 0.2.103.2131-192
* **Rust toolchain version:** 1.31.1
* **IDE name and version:** IDEA Community 2019.2
* **Operating system:** Linux

## Problem description

After a recent plugin update, format-on-save started to fail, giving an error on each save.

The event log shows:

```
Rustfmt is not installed
Install
```

Clicking on "Install" has no effect, the error comes back on the next save.

The following output appears on the command line:

```
WARN - rust.openapiext.CommandLineExt -         Execution failed (exit code 1).
        /home/nr/.cargo/bin/rustup component list --installed
        stdout :
        stderr : error: Found argument '--installed' which wasn't expected, or isn't valid in this context
```


Changed files:
src/main/kotlin/org/rust/cargo/toolchain/Rustup.kt

diff --git a/src/main/kotlin/org/rust/cargo/toolchain/Rustup.kt b/src/main/kotlin/org/rust/cargo/toolchain/Rustup.kt
index d64bc1c83..5d9ccb34c 100644
--- a/src/main/kotlin/org/rust/cargo/toolchain/Rustup.kt
+++ b/src/main/kotlin/org/rust/cargo/toolchain/Rustup.kt
@@ -25,16 +25,24 @@ class Rustup(
     private val rustup: Path,
     private val projectDirectory: Path
 ) {
-    fun listComponents(toolchain: String? = null, onlyInstalled: Boolean = false): List<String> =
+    data class Component(val name: String, val isInstalled: Boolean) {
+        companion object {
+            fun from(line: String): Component {
+                val name = line.substringBefore(' ')
+                val isInstalled = line.substringAfter(' ') in listOf("(installed)", "(default)")
+                return Component(name, isInstalled)
+            }
+        }
+    }
+
+    fun listComponents(): List<Component> =
         GeneralCommandLine(rustup)
             .withWorkDirectory(projectDirectory)
             .withParameters("component", "list")
-            .apply { if (onlyInstalled) addParameter("--installed") }
-            .apply { if (toolchain != null) addParameters("--toolchain", toolchain) }
             .execute()
             ?.stdoutLines
-            ?.map { it.substringBefore(' ') }
-            .orEmpty()
+            ?.map { Component.from(it) }
+            ?: emptyList()
 
     fun downloadStdlib(): DownloadResult<VirtualFile> {
         val downloadProcessOutput = GeneralCommandLine(rustup)
@@ -43,8 +51,7 @@ class Rustup(
             .execute(null)
 
         return if (downloadProcessOutput?.isSuccess == true) {
-            val sources = toolchain.getStdlibFromSysroot(projectDirectory)
-                ?: return DownloadResult.Err("Failed to find stdlib in sysroot")
+            val sources = toolchain.getStdlibFromSysroot(projectDirectory) ?: return DownloadResult.Err("Failed to find stdlib in sysroot")
             fullyRefreshDirectory(sources)
             DownloadResult.Ok(sources)
         } else {
@@ -87,8 +94,11 @@ class Rustup(
             val shortName = componentName.removeSuffix("-preview")
 
             val needInstall = run {
-                val rustup = project.toolchain?.rustup(cargoProjectDirectory) ?: return false
-                val isInstalled = rustup.listComponents(onlyInstalled = true).any { it.startsWith(shortName) }
+                val rustup = project.toolchain?.rustup(cargoProjectDirectory)
+                    ?: return false
+                val (_, isInstalled) = rustup.listComponents()
+                    .find { (name, _) -> name.startsWith(shortName) }
+                    ?: return false
                 !isInstalled
             }