Refactor workspace logic into workspace.rs (#16295)

## Summary

This is just a small refactor to move workspace related structs and impl
out from `server.rs` where `Server` is defined and into a new
`workspace.rs`.
This commit is contained in:
Dhruv Manilawala 2025-02-21 14:07:29 +05:30 committed by GitHub
parent 793264db13
commit c2b9fa84f7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 132 additions and 128 deletions

View file

@ -2,8 +2,9 @@
pub use edit::{DocumentKey, NotebookDocument, PositionEncoding, TextDocument};
use lsp_types::CodeActionKind;
pub use server::{Server, Workspace, Workspaces};
pub use server::Server;
pub use session::{ClientSettings, DocumentQuery, DocumentSnapshot, Session};
pub use workspace::{Workspace, Workspaces};
#[macro_use]
mod message;
@ -16,6 +17,7 @@ mod logging;
mod resolve;
mod server;
mod session;
mod workspace;
pub(crate) const SERVER_NAME: &str = "ruff";
pub(crate) const DIAGNOSTIC_NAME: &str = "Ruff";

View file

@ -3,14 +3,11 @@
use lsp_server as lsp;
use lsp_types as types;
use lsp_types::InitializeParams;
use lsp_types::WorkspaceFolder;
use std::num::NonZeroUsize;
use std::ops::Deref;
// The new PanicInfoHook name requires MSRV >= 1.82
#[allow(deprecated)]
use std::panic::PanicInfo;
use std::str::FromStr;
use thiserror::Error;
use types::ClientCapabilities;
use types::CodeActionKind;
use types::CodeActionOptions;
@ -24,7 +21,6 @@ use types::OneOf;
use types::TextDocumentSyncCapability;
use types::TextDocumentSyncKind;
use types::TextDocumentSyncOptions;
use types::Url;
use types::WorkDoneProgressOptions;
use types::WorkspaceFoldersServerCapabilities;
@ -34,9 +30,8 @@ use self::schedule::event_loop_thread;
use self::schedule::Scheduler;
use self::schedule::Task;
use crate::session::AllSettings;
use crate::session::ClientSettings;
use crate::session::Session;
use crate::session::WorkspaceSettingsMap;
use crate::workspace::Workspaces;
use crate::PositionEncoding;
mod api;
@ -447,122 +442,3 @@ impl FromStr for SupportedCommand {
})
}
}
#[derive(Debug)]
pub struct Workspaces(Vec<Workspace>);
impl Workspaces {
pub fn new(workspaces: Vec<Workspace>) -> Self {
Self(workspaces)
}
/// Create the workspaces from the provided workspace folders as provided by the client during
/// initialization.
fn from_workspace_folders(
workspace_folders: Option<Vec<WorkspaceFolder>>,
mut workspace_settings: WorkspaceSettingsMap,
) -> std::result::Result<Workspaces, WorkspacesError> {
let mut client_settings_for_url = |url: &Url| {
workspace_settings.remove(url).unwrap_or_else(|| {
tracing::info!(
"No workspace settings found for {}, using default settings",
url
);
ClientSettings::default()
})
};
let workspaces =
if let Some(folders) = workspace_folders.filter(|folders| !folders.is_empty()) {
folders
.into_iter()
.map(|folder| {
let settings = client_settings_for_url(&folder.uri);
Workspace::new(folder.uri).with_settings(settings)
})
.collect()
} else {
let current_dir = std::env::current_dir().map_err(WorkspacesError::Io)?;
tracing::info!(
"No workspace(s) were provided during initialization. \
Using the current working directory as a default workspace: {}",
current_dir.display()
);
let uri = Url::from_file_path(current_dir)
.map_err(|()| WorkspacesError::InvalidCurrentDir)?;
let settings = client_settings_for_url(&uri);
vec![Workspace::default(uri).with_settings(settings)]
};
Ok(Workspaces(workspaces))
}
}
impl Deref for Workspaces {
type Target = [Workspace];
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Error, Debug)]
enum WorkspacesError {
#[error(transparent)]
Io(#[from] std::io::Error),
#[error("Failed to create a URL from the current working directory")]
InvalidCurrentDir,
}
#[derive(Debug)]
pub struct Workspace {
/// The [`Url`] pointing to the root of the workspace.
url: Url,
/// The client settings for this workspace.
settings: Option<ClientSettings>,
/// Whether this is the default workspace as created by the server. This will be the case when
/// no workspace folders were provided during initialization.
is_default: bool,
}
impl Workspace {
/// Create a new workspace with the given root URL.
pub fn new(url: Url) -> Self {
Self {
url,
settings: None,
is_default: false,
}
}
/// Create a new default workspace with the given root URL.
pub fn default(url: Url) -> Self {
Self {
url,
settings: None,
is_default: true,
}
}
/// Set the client settings for this workspace.
#[must_use]
pub fn with_settings(mut self, settings: ClientSettings) -> Self {
self.settings = Some(settings);
self
}
/// Returns the root URL of the workspace.
pub(crate) fn url(&self) -> &Url {
&self.url
}
/// Returns the client settings for this workspace.
pub(crate) fn settings(&self) -> Option<&ClientSettings> {
self.settings.as_ref()
}
/// Returns true if this is the default workspace.
pub(crate) fn is_default(&self) -> bool {
self.is_default
}
}

View file

@ -7,7 +7,7 @@ use lsp_types::{ClientCapabilities, FileEvent, NotebookDocumentCellChange, Url};
use settings::ResolvedClientSettings;
use crate::edit::{DocumentKey, DocumentVersion, NotebookDocument};
use crate::server::Workspaces;
use crate::workspace::Workspaces;
use crate::{PositionEncoding, TextDocument};
pub(crate) use self::capabilities::ResolvedClientCapabilities;

View file

@ -11,7 +11,7 @@ use thiserror::Error;
pub(crate) use ruff_settings::RuffSettings;
use crate::edit::LanguageId;
use crate::server::{Workspace, Workspaces};
use crate::workspace::{Workspace, Workspaces};
use crate::{
edit::{DocumentKey, DocumentVersion, NotebookDocument},
PositionEncoding, TextDocument,

View file

@ -0,0 +1,126 @@
use std::ops::Deref;
use lsp_types::{Url, WorkspaceFolder};
use thiserror::Error;
use crate::session::WorkspaceSettingsMap;
use crate::ClientSettings;
#[derive(Debug)]
pub struct Workspaces(Vec<Workspace>);
impl Workspaces {
pub fn new(workspaces: Vec<Workspace>) -> Self {
Self(workspaces)
}
/// Create the workspaces from the provided workspace folders as provided by the client during
/// initialization.
pub(crate) fn from_workspace_folders(
workspace_folders: Option<Vec<WorkspaceFolder>>,
mut workspace_settings: WorkspaceSettingsMap,
) -> std::result::Result<Workspaces, WorkspacesError> {
let mut client_settings_for_url = |url: &Url| {
workspace_settings.remove(url).unwrap_or_else(|| {
tracing::info!(
"No workspace settings found for {}, using default settings",
url
);
ClientSettings::default()
})
};
let workspaces =
if let Some(folders) = workspace_folders.filter(|folders| !folders.is_empty()) {
folders
.into_iter()
.map(|folder| {
let settings = client_settings_for_url(&folder.uri);
Workspace::new(folder.uri).with_settings(settings)
})
.collect()
} else {
let current_dir = std::env::current_dir().map_err(WorkspacesError::Io)?;
tracing::info!(
"No workspace(s) were provided during initialization. \
Using the current working directory as a default workspace: {}",
current_dir.display()
);
let uri = Url::from_file_path(current_dir)
.map_err(|()| WorkspacesError::InvalidCurrentDir)?;
let settings = client_settings_for_url(&uri);
vec![Workspace::default(uri).with_settings(settings)]
};
Ok(Workspaces(workspaces))
}
}
impl Deref for Workspaces {
type Target = [Workspace];
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Error, Debug)]
pub(crate) enum WorkspacesError {
#[error(transparent)]
Io(#[from] std::io::Error),
#[error("Failed to create a URL from the current working directory")]
InvalidCurrentDir,
}
#[derive(Debug)]
pub struct Workspace {
/// The [`Url`] pointing to the root of the workspace.
url: Url,
/// The client settings for this workspace.
settings: Option<ClientSettings>,
/// Whether this is the default workspace as created by the server. This will be the case when
/// no workspace folders were provided during initialization.
is_default: bool,
}
impl Workspace {
/// Create a new workspace with the given root URL.
pub fn new(url: Url) -> Self {
Self {
url,
settings: None,
is_default: false,
}
}
/// Create a new default workspace with the given root URL.
pub fn default(url: Url) -> Self {
Self {
url,
settings: None,
is_default: true,
}
}
/// Set the client settings for this workspace.
#[must_use]
pub fn with_settings(mut self, settings: ClientSettings) -> Self {
self.settings = Some(settings);
self
}
/// Returns the root URL of the workspace.
pub(crate) fn url(&self) -> &Url {
&self.url
}
/// Returns the client settings for this workspace.
pub(crate) fn settings(&self) -> Option<&ClientSettings> {
self.settings.as_ref()
}
/// Returns true if this is the default workspace.
pub(crate) fn is_default(&self) -> bool {
self.is_default
}
}