diff --git a/Cargo.lock b/Cargo.lock index 83c1d95..8ae478d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,17 @@ dependencies = [ "memchr", ] +[[package]] +name = "alejandra" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2523e3312f47f4b28c443249c1d25fe7a71e4719198a8889fcc41a155032cb7f" +dependencies = [ + "mimalloc", + "rnix", + "rowan", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -61,6 +72,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + [[package]] name = "cfg-if" version = "0.1.10" @@ -295,6 +312,15 @@ version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +[[package]] +name = "libmimalloc-sys" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ca136052550448f55df7898c6dbe651c6b574fe38a0d9ea687a9f8088a2e2c" +dependencies = [ + "cc", +] + [[package]] name = "log" version = "0.4.17" @@ -356,6 +382,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mimalloc" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f64ad83c969af2e732e907564deb0d0ed393cec4af80776f77dd77a1a427698" +dependencies = [ + "libmimalloc-sys", +] + [[package]] name = "nixpkgs-fmt-rnix" version = "1.2.0" @@ -462,6 +497,7 @@ dependencies = [ name = "rnix-lsp" version = "0.3.0-dev" dependencies = [ + "alejandra", "dirs", "env_logger", "gc", diff --git a/Cargo.toml b/Cargo.toml index 39d5233..3794f7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,10 +20,11 @@ log = "0.4.17" lsp-server = "0.6.0" lsp-types = { version = "0.93.0", features = ["proposed"] } regex = "1.5.6" +alejandra = { version = "1.5.0", optional = true } rnix = "0.10.2" serde = "1.0.138" serde_json = "1.0.82" -nixpkgs-fmt-rnix = "1.2.0" +nixpkgs-fmt-rnix = { version = "1.2.0", optional = true } [dev-dependencies] stoppable_thread = "0.2.1" @@ -32,7 +33,7 @@ maplit = "1" [features] # Set this to ["verbose"] when debugging -default = [] +default = [ "nixpkgs-fmt-rnix" ] # Enable showing internal errors via editor UI, such as via hover popups. # This can be helpful for debugging, but we don't want the evaluator to diff --git a/src/main.rs b/src/main.rs index 6f92189..88c8f0a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -209,16 +209,40 @@ impl App { let document_links = self.document_links(¶ms).unwrap_or_default(); self.reply(Response::new_ok(id, document_links)); } else if let Some((id, params)) = cast::(&mut req) { - let changes = if let Some((ast, code, _)) = self.files.get(¶ms.text_document.uri) { - let fmt = nixpkgs_fmt::reformat_node(&ast.node()); - vec![TextEdit { - range: utils::range(&code, TextRange::up_to(ast.node().text().len())), - new_text: fmt.text().to_string(), - }] + if let Some((ast, code, _)) = self.files.get(¶ms.text_document.uri) { + let node = ast.node(); + let range = utils::range(&code, TextRange::up_to(node.text().len())); + if cfg!(feature = "alejandra") { + #[cfg(feature = "alejandra")] + match alejandra::format::in_memory( + params.text_document.uri.to_string(), + code.to_string(), + ) { + (alejandra::format::Status::Changed(true), new_text) => { + self.reply(Response::new_ok(id, vec![TextEdit { range, new_text }])) + } + (alejandra::format::Status::Changed(false), _) => { + self.reply(Response::new_ok(id, ())) + } + (alejandra::format::Status::Error(e), _) => { + self.reply(Response::new_err(id, ErrorCode::InternalError as i32, e)) + } + } + } else if cfg!(feature = "nixpkgs-fmt-rnix") { + #[cfg(feature = "nixpkgs-fmt-rnix")] + self.reply(Response::new_ok( + id, + vec![TextEdit { + range, + new_text: nixpkgs_fmt::reformat_node(&node).text().to_string(), + }], + )); + } else { + self.reply(Response::new_ok(id, ())) + } } else { - Vec::new() - }; - self.reply(Response::new_ok(id, changes)); + self.reply(Response::new_ok(id, ())) + } } else if let Some((id, params)) = cast::(&mut req) { if let Some((range, markdown)) = self.hover(params) { self.reply(Response::new_ok(