Skip to content

Commit

Permalink
Extract creating workspaces in the server
Browse files Browse the repository at this point in the history
  • Loading branch information
dhruvmanila committed Oct 16, 2024
1 parent c6b311c commit 8dd2a31
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 49 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/ruff_server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ rustc-hash = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
shellexpand = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }

Expand Down
2 changes: 1 addition & 1 deletion crates/ruff_server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

pub use edit::{DocumentKey, NotebookDocument, PositionEncoding, TextDocument};
use lsp_types::CodeActionKind;
pub use server::Server;
pub use server::{Server, Workspace, Workspaces};
pub use session::{ClientSettings, DocumentQuery, DocumentSnapshot, Session};

#[macro_use]
Expand Down
169 changes: 139 additions & 30 deletions crates/ruff_server/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

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;
use std::panic::PanicInfo;
use std::str::FromStr;
use thiserror::Error;
use types::ClientCapabilities;
use types::CodeActionKind;
use types::CodeActionOptions;
Expand All @@ -18,6 +22,7 @@ use types::OneOf;
use types::TextDocumentSyncCapability;
use types::TextDocumentSyncKind;
use types::TextDocumentSyncOptions;
use types::Url;
use types::WorkDoneProgressOptions;
use types::WorkspaceFoldersServerCapabilities;

Expand All @@ -29,6 +34,7 @@ use self::schedule::Task;
use crate::session::AllSettings;
use crate::session::ClientSettings;
use crate::session::Session;
use crate::session::WorkspaceSettingsMap;
use crate::PositionEncoding;

mod api;
Expand Down Expand Up @@ -71,17 +77,23 @@ impl Server {

crate::message::init_messenger(connection.make_sender());

let InitializeParams {
initialization_options,
workspace_folders,
client_info,
..
} = init_params;

let mut all_settings = AllSettings::from_value(
init_params
.initialization_options
initialization_options
.unwrap_or_else(|| serde_json::Value::Object(serde_json::Map::default())),
);
if let Some(preview) = preview {
all_settings.set_preview(preview);
}
let AllSettings {
global_settings,
mut workspace_settings,
workspace_settings,
} = all_settings;

crate::trace::init_tracing(
Expand All @@ -91,34 +103,13 @@ impl Server {
.log_level
.unwrap_or(crate::trace::LogLevel::Info),
global_settings.tracing.log_file.as_deref(),
init_params.client_info.as_ref(),
client_info.as_ref(),
);

let mut workspace_for_url = |url: lsp_types::Url| {
let Some(workspace_settings) = workspace_settings.as_mut() else {
return (url, ClientSettings::default());
};
let settings = workspace_settings.remove(&url).unwrap_or_else(|| {
tracing::warn!("No workspace settings found for {}", url);
ClientSettings::default()
});
(url, settings)
};

let workspaces = init_params
.workspace_folders
.filter(|folders| !folders.is_empty())
.map(|folders| folders.into_iter().map(|folder| {
workspace_for_url(folder.uri)
}).collect())
.or_else(|| {
tracing::warn!("No workspace(s) were provided during initialization. Using the current working directory as a default workspace...");
let uri = types::Url::from_file_path(std::env::current_dir().ok()?).ok()?;
Some(vec![workspace_for_url(uri)])
})
.ok_or_else(|| {
anyhow::anyhow!("Failed to get the current working directory while creating a default workspace.")
})?;
let workspaces = Workspaces::from_workspace_folders(
workspace_folders,
workspace_settings.unwrap_or_default(),
)?;

Ok(Self {
connection,
Expand All @@ -127,7 +118,7 @@ impl Server {
&client_capabilities,
position_encoding,
global_settings,
workspaces,
&workspaces,
)?,
client_capabilities,
})
Expand Down Expand Up @@ -462,3 +453,121 @@ 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.
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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl super::SyncNotificationHandler for DidChangeWorkspace {
) -> Result<()> {
for types::WorkspaceFolder { uri, .. } in params.event.added {
session
.open_workspace_folder(&uri)
.open_workspace_folder(uri)
.with_failure_code(lsp_server::ErrorCode::InvalidParams)?;
}
for types::WorkspaceFolder { uri, .. } in params.event.removed {
Expand Down
9 changes: 5 additions & 4 deletions crates/ruff_server/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ use std::sync::Arc;
use lsp_types::{ClientCapabilities, NotebookDocumentCellChange, Url};

use crate::edit::{DocumentKey, DocumentVersion, NotebookDocument};
use crate::server::Workspaces;
use crate::{PositionEncoding, TextDocument};

pub(crate) use self::capabilities::ResolvedClientCapabilities;
pub use self::index::DocumentQuery;
pub(crate) use self::settings::AllSettings;
pub use self::settings::ClientSettings;
pub(crate) use self::settings::{AllSettings, WorkspaceSettingsMap};

mod capabilities;
mod index;
Expand Down Expand Up @@ -42,11 +43,11 @@ impl Session {
client_capabilities: &ClientCapabilities,
position_encoding: PositionEncoding,
global_settings: ClientSettings,
workspace_folders: Vec<(Url, ClientSettings)>,
workspaces: &Workspaces,
) -> crate::Result<Self> {
Ok(Self {
position_encoding,
index: index::Index::new(workspace_folders, &global_settings)?,
index: index::Index::new(workspaces, &global_settings)?,
global_settings,
resolved_client_capabilities: Arc::new(ResolvedClientCapabilities::new(
client_capabilities,
Expand Down Expand Up @@ -136,7 +137,7 @@ impl Session {
}

/// Open a workspace folder at the given `url`.
pub(crate) fn open_workspace_folder(&mut self, url: &Url) -> crate::Result<()> {
pub(crate) fn open_workspace_folder(&mut self, url: Url) -> crate::Result<()> {
self.index.open_workspace_folder(url, &self.global_settings)
}

Expand Down
20 changes: 11 additions & 9 deletions crates/ruff_server/src/session/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use rustc_hash::FxHashMap;
pub(crate) use ruff_settings::RuffSettings;

use crate::edit::LanguageId;
use crate::server::{Workspace, Workspaces};
use crate::{
edit::{DocumentKey, DocumentVersion, NotebookDocument},
PositionEncoding, TextDocument,
Expand Down Expand Up @@ -67,12 +68,12 @@ pub enum DocumentQuery {

impl Index {
pub(super) fn new(
workspace_folders: Vec<(Url, ClientSettings)>,
workspaces: &Workspaces,
global_settings: &ClientSettings,
) -> crate::Result<Self> {
let mut settings = WorkspaceSettingsIndex::default();
for (url, workspace_settings) in workspace_folders {
settings.register_workspace(&url, Some(workspace_settings), global_settings)?;
for workspace in &**workspaces {
settings.register_workspace(workspace, global_settings)?;
}

Ok(Self {
Expand Down Expand Up @@ -167,11 +168,12 @@ impl Index {

pub(super) fn open_workspace_folder(
&mut self,
url: &Url,
url: Url,
global_settings: &ClientSettings,
) -> crate::Result<()> {
// TODO(jane): Find a way for workspace client settings to be added or changed dynamically.
self.settings.register_workspace(url, None, global_settings)
self.settings
.register_workspace(&Workspace::new(url), global_settings)
}

pub(super) fn num_documents(&self) -> usize {
Expand Down Expand Up @@ -398,10 +400,10 @@ impl WorkspaceSettingsIndex {
/// workspace. Otherwise, the global settings are used exclusively.
fn register_workspace(
&mut self,
workspace_url: &Url,
workspace_settings: Option<ClientSettings>,
workspace: &Workspace,
global_settings: &ClientSettings,
) -> crate::Result<()> {
let workspace_url = workspace.url();
if workspace_url.scheme() != "file" {
tracing::info!("Ignoring non-file workspace URL: {workspace_url}");
show_warn_msg!("Ruff does not support non-file workspaces; Ignoring {workspace_url}");
Expand All @@ -411,8 +413,8 @@ impl WorkspaceSettingsIndex {
anyhow!("Failed to convert workspace URL to file path: {workspace_url}")
})?;

let client_settings = if let Some(workspace_settings) = workspace_settings {
ResolvedClientSettings::with_workspace(&workspace_settings, global_settings)
let client_settings = if let Some(workspace_settings) = workspace.settings() {
ResolvedClientSettings::with_workspace(workspace_settings, global_settings)
} else {
ResolvedClientSettings::global(global_settings)
};
Expand Down
8 changes: 4 additions & 4 deletions crates/ruff_server/tests/notebook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use lsp_types::{
Position, Range, TextDocumentContentChangeEvent, VersionedTextDocumentIdentifier,
};
use ruff_notebook::SourceValue;
use ruff_server::ClientSettings;
use ruff_server::{ClientSettings, Workspace, Workspaces};

const SUPER_RESOLUTION_OVERVIEW_PATH: &str =
"./resources/test/fixtures/tensorflow_test_notebook.ipynb";
Expand All @@ -32,10 +32,10 @@ fn super_resolution_overview() {
&ClientCapabilities::default(),
ruff_server::PositionEncoding::UTF16,
ClientSettings::default(),
vec![(
&Workspaces::new(vec![Workspace::new(
lsp_types::Url::from_file_path(file_path.parent().unwrap()).unwrap(),
ClientSettings::default(),
)],
)
.with_settings(ClientSettings::default())]),
)
.unwrap();

Expand Down

0 comments on commit 8dd2a31

Please sign in to comment.