From 6ac966899853f03ab572ccd2cee8bf5b2a66aaea Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Wed, 1 Apr 2020 13:31:12 +0200
Subject: [PATCH] Generalize rustfmt config

---
 crates/rust-analyzer/src/main_loop.rs         |  4 +--
 .../rust-analyzer/src/main_loop/handlers.rs   | 27 +++++++++++++------
 crates/rust-analyzer/src/world.rs             | 20 +++++++++++++-
 3 files changed, 40 insertions(+), 11 deletions(-)

diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index a89ea86ead4..753dc7d50b3 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -38,7 +38,7 @@ use crate::{
         subscriptions::Subscriptions,
     },
     req,
-    world::{Config, WorldSnapshot, WorldState},
+    world::{Config, RustfmtConfig, WorldSnapshot, WorldState},
     Result, ServerConfig,
 };
 use req::ConfigurationParams;
@@ -110,7 +110,7 @@ fn get_config(
         } else {
             None
         },
-        rustfmt_args: config.rustfmt_args.clone(),
+        rustfmt: RustfmtConfig::Rustfmt { extra_args: config.rustfmt_args.clone() },
         vscode_lldb: config.vscode_lldb,
         proc_macro_srv: None, // FIXME: get this from config
     }
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs
index d5cb5d13720..80d96f89e31 100644
--- a/crates/rust-analyzer/src/main_loop/handlers.rs
+++ b/crates/rust-analyzer/src/main_loop/handlers.rs
@@ -39,7 +39,7 @@ use crate::{
     from_json,
     req::{self, Decoration, InlayHint, InlayHintsParams},
     semantic_tokens::SemanticTokensBuilder,
-    world::WorldSnapshot,
+    world::{RustfmtConfig, WorldSnapshot},
     LspError, Result,
 };
 
@@ -610,13 +610,24 @@ pub fn handle_formatting(
     let file_line_index = world.analysis().file_line_index(file_id)?;
     let end_position = TextUnit::of_str(&file).conv_with(&file_line_index);
 
-    let mut rustfmt = process::Command::new("rustfmt");
-    rustfmt.args(&world.config.rustfmt_args);
-    if let Some(&crate_id) = crate_ids.first() {
-        // Assume all crates are in the same edition
-        let edition = world.analysis().crate_edition(crate_id)?;
-        rustfmt.args(&["--edition", &edition.to_string()]);
-    }
+    let mut rustfmt = match &world.config.rustfmt {
+        RustfmtConfig::Rustfmt { extra_args } => {
+            let mut cmd = process::Command::new("rustfmt");
+            cmd.args(extra_args);
+            if let Some(&crate_id) = crate_ids.first() {
+                // Assume all crates are in the same edition
+                let edition = world.analysis().crate_edition(crate_id)?;
+                cmd.arg("--edition");
+                cmd.arg(edition.to_string());
+            }
+            cmd
+        }
+        RustfmtConfig::CustomCommand { command, args } => {
+            let mut cmd = process::Command::new(command);
+            cmd.args(args);
+            cmd
+        }
+    };
 
     if let Ok(path) = params.text_document.uri.to_file_path() {
         if let Some(parent) = path.parent() {
diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs
index 2db058eb120..ccdf3710cd0 100644
--- a/crates/rust-analyzer/src/world.rs
+++ b/crates/rust-analyzer/src/world.rs
@@ -57,12 +57,30 @@ pub struct Config {
     pub supports_location_link: bool,
     pub line_folding_only: bool,
     pub inlay_hints: InlayHintsConfig,
-    pub rustfmt_args: Vec<String>,
+    pub rustfmt: RustfmtConfig,
     pub check: Option<FlycheckConfig>,
     pub vscode_lldb: bool,
     pub proc_macro_srv: Option<String>,
 }
 
+#[derive(Debug, Clone)]
+pub enum RustfmtConfig {
+    Rustfmt {
+        extra_args: Vec<String>,
+    },
+    #[allow(unused)]
+    CustomCommand {
+        command: String,
+        args: Vec<String>,
+    },
+}
+
+impl Default for RustfmtConfig {
+    fn default() -> Self {
+        RustfmtConfig::Rustfmt { extra_args: Vec::new() }
+    }
+}
+
 /// `WorldState` is the primary mutable state of the language server
 ///
 /// The most interesting components are `vfs`, which stores a consistent