diff --git a/Cargo.lock b/Cargo.lock index cf8f5ae..6e31a9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,15 +4,15 @@ version = 3 [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "cfg-if" @@ -28,9 +28,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" [[package]] name = "heck" @@ -49,9 +49,9 @@ checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" [[package]] name = "indexmap" -version = "2.2.6" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", "hashbrown", @@ -66,9 +66,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "leb128" @@ -78,9 +78,15 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "nu-ansi-term" @@ -94,9 +100,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "overload" @@ -112,48 +118,48 @@ checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", @@ -162,11 +168,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -188,18 +195,18 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "spdx" -version = "0.10.4" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ef1a0fa1e39ac22972c8db23ff89aea700ab96aa87114e1fb55937a631a0c9" +checksum = "47317bbaf63785b53861e1ae2d11b80d6b624211d42cb20efcd210ee6f8a14bc" dependencies = [ "smallvec", ] [[package]] name = "syn" -version = "2.0.58" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -275,21 +282,21 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "valuable" @@ -449,7 +456,7 @@ dependencies = [ [[package]] name = "zed_biome" -version = "0.1.2" +version = "0.1.3" dependencies = [ "log", "tracing", @@ -459,9 +466,9 @@ dependencies = [ [[package]] name = "zed_extension_api" -version = "0.0.6" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca8bcaea3feb2d2ce9dbeb061ee48365312a351faa7014c417b0365fe9e459" +checksum = "594fd10dd0f2f853eb243e2425e7c95938cef49adb81d9602921d002c5e6d9d9" dependencies = [ "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 892fc36..deaebee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ edition = "2021" license = "MIT" name = "zed_biome" publish = false -version = "0.1.2" +version = "0.1.3" [lib] crate-type = ["cdylib"] @@ -13,4 +13,4 @@ path = "src/biome.rs" log = "0.4.21" tracing = "0.1.40" tracing-subscriber = "0.3.18" -zed_extension_api = "0.0.6" +zed_extension_api = "0.1.0" diff --git a/src/biome.rs b/src/biome.rs index ccd71dc..740e870 100644 --- a/src/biome.rs +++ b/src/biome.rs @@ -1,7 +1,4 @@ -use std::{ - env, fs, - path::{Path, PathBuf}, -}; +use std::path::{Path, PathBuf}; use zed::settings::LspSettings; use zed_extension_api::{ self as zed, @@ -9,7 +6,7 @@ use zed_extension_api::{ LanguageServerId, Result, }; -const SERVER_PATH: &str = "node_modules/@biomejs/biome/bin/biome"; +const WORKTREE_SERVER_PATH: &str = "node_modules/@biomejs/biome/bin/biome"; const PACKAGE_NAME: &str = "@biomejs/biome"; const BIOME_CONFIG_PATHS: &[&str] = &["biome.json", "biome.jsonc"]; @@ -17,8 +14,8 @@ const BIOME_CONFIG_PATHS: &[&str] = &["biome.json", "biome.jsonc"]; struct BiomeExtension; impl BiomeExtension { - fn server_exists(&self, path: &PathBuf) -> bool { - fs::metadata(path).map_or(false, |stat| stat.is_file()) + fn extension_server_exists(&self, path: &PathBuf) -> bool { + std::fs::metadata(path).map_or(false, |stat| stat.is_file()) } fn binary_specifier(&self) -> Result { @@ -45,43 +42,31 @@ impl BiomeExtension { )) } - fn server_script_path( - &mut self, - language_server_id: &LanguageServerId, - worktree: &zed::Worktree, - ) -> Result { + fn worktree_biome_exists(&self, worktree: &zed::Worktree) -> bool { // This is a workaround, as reading the file from wasm doesn't work. // Instead we try to read the `package.json`, see if `@biomejs/biome` is installed let package_json = worktree .read_text_file("package.json") .unwrap_or(String::from(r#"{}"#)); + let package_json: Option = serde_json::from_str(package_json.as_str()).ok(); - let server_package_exists = package_json.is_some_and(|f| { + package_json.is_some_and(|f| { !f["dependencies"][PACKAGE_NAME].is_null() || !f["devDependencies"][PACKAGE_NAME].is_null() - }); - - if server_package_exists { - let worktree_root_path = worktree.root_path(); - - return Ok( - Path::new(worktree_root_path.as_str()) - .join(SERVER_PATH) - .to_string_lossy() - .to_string(), - ); - } + }) + } + fn check_biome_updates(&mut self, language_server_id: &LanguageServerId) -> Result<()> { // fallback to extension owned biome zed::set_language_server_installation_status( language_server_id, &zed::LanguageServerInstallationStatus::CheckingForUpdate, ); - let fallback_server_path = &Path::new("./node_modules").join(self.binary_specifier()?); + let extension_server_path = &Path::new("./node_modules").join(self.binary_specifier()?); let version = zed::npm_package_latest_version(PACKAGE_NAME)?; - if !self.server_exists(fallback_server_path) + if !self.extension_server_exists(extension_server_path) || zed::npm_package_installed_version(PACKAGE_NAME)?.as_ref() != Some(&version) { zed::set_language_server_installation_status( @@ -91,14 +76,14 @@ impl BiomeExtension { let result = zed::npm_install_package(PACKAGE_NAME, &version); match result { Ok(()) => { - if !self.server_exists(fallback_server_path) { + if !self.extension_server_exists(extension_server_path) { Err(format!( - "installed package '{PACKAGE_NAME}' did not contain expected path '{fallback_server_path:?}'", + "installed package '{PACKAGE_NAME}' did not contain expected path '{extension_server_path:?}'", ))?; } } Err(error) => { - if !self.server_exists(fallback_server_path) { + if !self.extension_server_exists(extension_server_path) { Err(format!( "failed to install package '{PACKAGE_NAME}': {error}" ))?; @@ -107,7 +92,7 @@ impl BiomeExtension { } } - Ok(fallback_server_path.to_string_lossy().to_string()) + Ok(()) } // Returns the path if a config file exists @@ -142,43 +127,60 @@ impl zed::Extension for BiomeExtension { language_server_id: &LanguageServerId, worktree: &zed::Worktree, ) -> Result { - let path = self.server_script_path(language_server_id, worktree)?; let settings = LspSettings::for_worktree(language_server_id.as_ref(), worktree)?; let mut args = vec!["lsp-proxy".to_string()]; + // evaluate lsp settings if let Some(settings) = settings.settings { - let config_path = self.config_path(worktree, &settings); - let require_config_file = settings .get("require_config_file") .and_then(|value| value.as_bool()) .unwrap_or(false); - if let Some(config_path) = config_path { - args.push("--config-path".to_string()); - args.push(config_path.clone()); + if let Some(config_path) = self.config_path(worktree, &settings) { + args.append(&mut vec!["--config-path".to_string(), config_path.clone()]); } else if require_config_file { return Err("biome.json is not found but require_config_file is true".to_string()); } } - let bin = env::current_dir() - .unwrap() - .join(path) - .to_string_lossy() - .to_string(); - + // check and run biome with custom binary if let Some(binary) = settings.binary { return Ok(zed::Command { - command: binary.path.map_or(bin, |path| path), + command: binary + .path + .map_or(WORKTREE_SERVER_PATH.to_string(), |path| path), args: binary.arguments.map_or(args, |args| args), env: Default::default(), }); } + // try to run from worktree biome package + if self.worktree_biome_exists(worktree) { + let server_path = Path::new(worktree.root_path().as_str()) + .join(WORKTREE_SERVER_PATH) + .to_string_lossy() + .to_string(); + + let mut node_args = vec![server_path]; + node_args.append(&mut args); + + return Ok(zed::Command { + command: zed::node_binary_path()?, + args: node_args, + env: Default::default(), + }); + } + + // install/update and run biome for extension + self.check_biome_updates(language_server_id)?; + + let mut server_path = PathBuf::from("./node_modules"); + server_path.push(self.binary_specifier()?); + Ok(zed::Command { - command: bin, + command: server_path.to_string_lossy().to_string(), args, env: Default::default(), })