diff --git a/CHANGELOG.md b/CHANGELOG.md index c5bf7f0629cb..06366184fa6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,8 +51,8 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b - `--log-path`: a directory where to store the daemon logs. The commands also accepts the environment variable `BIOME_LOG_PATH`. - `--log-prefix-name`: a prefix that's added to the file name of the logs. It defaults to `server.log`. The commands also accepts the environment variable `BIOME_LOG_PREFIX_NAME`. - @Contributed by @ematipico - + Contributed by @ematipico + #### Enhancements @@ -106,6 +106,21 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b - Fix [#3577](https://github.com/biomejs/biome/issues/3577), where the update of the configuration file was resulting in the creation of a new internal project. Contributed by @ematipico +#### Enhancements + +- When an LSP is not able to provide a [`rootUri` or a `workspaceFolders`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize), the Biome LSP will use the **user home directory** as working directory. + The user home directory differs based on the OS: + + | Platform | Value | Example | + |----------|------------------------|------------------| + | Linux | `$HOME` | `/home/alice` | + | macOS | `$HOME` | `/home/alice` | + | Windows | `{FOLDERID_Profile}` | `C:\Users\Alice` | + + If the LSP can't retrieve the user directory, it will fall back to the root directory. + + Contributed by @ematipico + ### Formatter #### Enhancements diff --git a/Cargo.lock b/Cargo.lock index c67e650fb464..683be97fa565 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -901,6 +901,7 @@ dependencies = [ "biome_rowan", "biome_service", "biome_text_edit", + "directories", "futures", "rustc-hash 1.1.0", "serde", diff --git a/Cargo.toml b/Cargo.toml index 7536973cf5d6..3f16c7cb704a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -163,6 +163,7 @@ bpaf = { version = "0.9.12", features = ["derive"] } countme = "3.0.1" crossbeam = "0.8.4" dashmap = "5.5.3" +directories = "5.0.1" enumflags2 = "0.7.10" getrandom = "0.2.15" ignore = "0.4.22" diff --git a/crates/biome_cli/tests/commands/check.rs b/crates/biome_cli/tests/commands/check.rs index 8e054af164a1..5af88c83212c 100644 --- a/crates/biome_cli/tests/commands/check.rs +++ b/crates/biome_cli/tests/commands/check.rs @@ -840,7 +840,9 @@ fn fs_error_dereferenced_symlink() { } let result = run_cli( - DynRef::Owned(Box::new(OsFileSystem::new(root_path.clone()))), + DynRef::Owned(Box::new( + OsFileSystem::new().with_working_directory(root_path.clone()), + )), &mut console, Args::from([("check"), root_path.display().to_string().as_str()].as_slice()), ); @@ -884,7 +886,9 @@ fn fs_error_infinite_symlink_expansion_to_dirs() { } let result = run_cli( - DynRef::Owned(Box::new(OsFileSystem::new(root_path.clone()))), + DynRef::Owned(Box::new( + OsFileSystem::new().with_working_directory(root_path.clone()), + )), &mut console, Args::from([("check"), (root_path.display().to_string().as_str())].as_slice()), ); @@ -930,7 +934,9 @@ fn fs_error_infinite_symlink_expansion_to_files() { } let result = run_cli( - DynRef::Owned(Box::new(OsFileSystem::new(root_path.clone()))), + DynRef::Owned(Box::new( + OsFileSystem::new().with_working_directory(root_path.clone()), + )), &mut console, Args::from([("check"), (root_path.display().to_string().as_str())].as_slice()), ); @@ -1110,7 +1116,9 @@ fn fs_files_ignore_symlink() { } let result = run_cli( - DynRef::Owned(Box::new(OsFileSystem::new(root_path.clone()))), + DynRef::Owned(Box::new( + OsFileSystem::new().with_working_directory(root_path.clone()), + )), &mut console, Args::from( [ diff --git a/crates/biome_cli/tests/commands/lint.rs b/crates/biome_cli/tests/commands/lint.rs index b3a7a4578f86..0410b176f907 100644 --- a/crates/biome_cli/tests/commands/lint.rs +++ b/crates/biome_cli/tests/commands/lint.rs @@ -866,7 +866,9 @@ fn fs_error_dereferenced_symlink() { } let result = run_cli( - DynRef::Owned(Box::new(OsFileSystem::new(root_path.clone()))), + DynRef::Owned(Box::new( + OsFileSystem::new().with_working_directory(root_path.clone()), + )), &mut console, Args::from([("lint"), root_path.display().to_string().as_str()].as_slice()), ); @@ -910,7 +912,9 @@ fn fs_error_infinite_symlink_expansion_to_dirs() { } let result = run_cli( - DynRef::Owned(Box::new(OsFileSystem::new(root_path.clone()))), + DynRef::Owned(Box::new( + OsFileSystem::new().with_working_directory(root_path.clone()), + )), &mut console, Args::from([("lint"), (root_path.display().to_string().as_str())].as_slice()), ); @@ -956,7 +960,9 @@ fn fs_error_infinite_symlink_expansion_to_files() { } let result = run_cli( - DynRef::Owned(Box::new(OsFileSystem::new(root_path.clone()))), + DynRef::Owned(Box::new( + OsFileSystem::new().with_working_directory(root_path.clone()), + )), &mut console, Args::from([("lint"), (root_path.display().to_string().as_str())].as_slice()), ); @@ -1137,7 +1143,9 @@ fn fs_files_ignore_symlink() { } let result = run_cli( - DynRef::Owned(Box::new(OsFileSystem::new(root_path.clone()))), + DynRef::Owned(Box::new( + OsFileSystem::new().with_working_directory(root_path.clone()), + )), &mut console, Args::from( [ @@ -1189,7 +1197,9 @@ fn include_files_in_subdir() { .unwrap(); let result = run_cli( - DynRef::Owned(Box::new(OsFileSystem::new(root_path.clone()))), + DynRef::Owned(Box::new( + OsFileSystem::new().with_working_directory(root_path.clone()), + )), &mut console, Args::from([("lint"), root_path.display().to_string().as_str()].as_slice()), ); @@ -1247,7 +1257,9 @@ fn include_files_in_symlinked_subdir() { } let result = run_cli( - DynRef::Owned(Box::new(OsFileSystem::new(subroot_path.clone()))), + DynRef::Owned(Box::new( + OsFileSystem::new().with_working_directory(subroot_path.clone()), + )), &mut console, Args::from([("lint"), subroot_path.display().to_string().as_str()].as_slice()), ); @@ -1307,7 +1319,9 @@ fn ignore_file_in_subdir_in_symlinked_dir() { } let result = run_cli( - DynRef::Owned(Box::new(OsFileSystem::new(subroot_path.clone()))), + DynRef::Owned(Box::new( + OsFileSystem::new().with_working_directory(subroot_path.clone()), + )), &mut console, Args::from([("lint"), subroot_path.display().to_string().as_str()].as_slice()), ); diff --git a/crates/biome_fs/Cargo.toml b/crates/biome_fs/Cargo.toml index f790c4c4fe5d..9244532457bf 100644 --- a/crates/biome_fs/Cargo.toml +++ b/crates/biome_fs/Cargo.toml @@ -15,7 +15,7 @@ version = "0.5.7" [dependencies] biome_diagnostics = { workspace = true } crossbeam = { workspace = true } -directories = "5.0.1" +directories = { workspace = true } indexmap = { workspace = true } oxc_resolver = { workspace = true } parking_lot = { version = "0.12.3", features = ["arc_lock"] } diff --git a/crates/biome_fs/src/fs/os.rs b/crates/biome_fs/src/fs/os.rs index 977b0d2011a5..ec979fc4ef2b 100644 --- a/crates/biome_fs/src/fs/os.rs +++ b/crates/biome_fs/src/fs/os.rs @@ -28,9 +28,9 @@ pub struct OsFileSystem { } impl OsFileSystem { - pub fn new(working_directory: PathBuf) -> Self { + pub fn new() -> Self { Self { - working_directory: Some(working_directory), + working_directory: None, configuration_resolver: AssertUnwindSafe(Resolver::new(ResolveOptions { condition_names: vec!["node".to_string(), "import".to_string()], extensions: vec![".json".to_string(), ".jsonc".to_string()], @@ -38,6 +38,11 @@ impl OsFileSystem { })), } } + + pub fn with_working_directory(mut self, working_directory: impl Into>) -> Self { + self.working_directory = working_directory.into(); + self + } } impl Default for OsFileSystem { diff --git a/crates/biome_lsp/Cargo.toml b/crates/biome_lsp/Cargo.toml index c9ddec595669..47aeaec2c8aa 100644 --- a/crates/biome_lsp/Cargo.toml +++ b/crates/biome_lsp/Cargo.toml @@ -23,6 +23,7 @@ biome_fs = { workspace = true } biome_rowan = { workspace = true } biome_service = { workspace = true } biome_text_edit = { workspace = true } +directories = { workspace = true } futures = "0.3.30" rustc-hash = { workspace = true } serde = { workspace = true, features = ["derive"] } diff --git a/crates/biome_lsp/src/server.rs b/crates/biome_lsp/src/server.rs index b0e815b3e861..25ab55a796e0 100644 --- a/crates/biome_lsp/src/server.rs +++ b/crates/biome_lsp/src/server.rs @@ -13,10 +13,12 @@ use biome_service::workspace::{ RageEntry, RageParams, RageResult, RegisterProjectFolderParams, UnregisterProjectFolderParams, }; use biome_service::{workspace, DynRef, Workspace}; +use directories::UserDirs; use futures::future::ready; use futures::FutureExt; use rustc_hash::FxHashMap; use serde_json::json; +use std::env; use std::panic::RefUnwindSafe; use std::path::PathBuf; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; @@ -560,7 +562,11 @@ impl ServerFactory { } pub fn create(&self, config_path: Option) -> ServerConnection { - self.create_with_fs(config_path, DynRef::Owned(Box::::default())) + let base_path = UserDirs::new() + .map(|dir| dir.home_dir().to_path_buf()) + .or(env::current_dir().ok()); + let fs = OsFileSystem::new().with_working_directory(base_path); + self.create_with_fs(config_path, DynRef::Owned(Box::new(fs))) } /// Create a new [ServerConnection] from this factory