Compare commits
1 Commits
alex/subsc
...
dhruv/work
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d0468137c |
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -2833,6 +2833,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"shellexpand",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
@@ -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 }
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
pub use edit::{DocumentKey, NotebookDocument, PositionEncoding, TextDocument};
|
||||
use lsp_types::CodeActionKind;
|
||||
pub use server::Server;
|
||||
pub use server::{Server, Workspaces};
|
||||
pub use session::{ClientSettings, DocumentQuery, DocumentSnapshot, Session};
|
||||
|
||||
#[macro_use]
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -71,9 +77,15 @@ 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 {
|
||||
@@ -81,7 +93,7 @@ impl Server {
|
||||
}
|
||||
let AllSettings {
|
||||
global_settings,
|
||||
mut workspace_settings,
|
||||
workspace_settings,
|
||||
} = all_settings;
|
||||
|
||||
crate::trace::init_tracing(
|
||||
@@ -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,
|
||||
@@ -127,7 +118,7 @@ impl Server {
|
||||
&client_capabilities,
|
||||
position_encoding,
|
||||
global_settings,
|
||||
workspaces,
|
||||
&workspaces,
|
||||
)?,
|
||||
client_capabilities,
|
||||
})
|
||||
@@ -462,3 +453,117 @@ impl FromStr for SupportedCommand {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Workspaces(Vec<Workspace>);
|
||||
|
||||
impl 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(crate) fn new(url: Url) -> Self {
|
||||
Self {
|
||||
url,
|
||||
settings: None,
|
||||
is_default: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new default workspace with the given root URL.
|
||||
fn default(url: Url) -> Self {
|
||||
Self {
|
||||
url,
|
||||
settings: None,
|
||||
is_default: true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the client settings for this workspace.
|
||||
fn with_settings(mut self, settings: ClientSettings) -> Self {
|
||||
self.settings = Some(settings);
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns the root URL of the workspace.
|
||||
pub fn url(&self) -> &Url {
|
||||
&self.url
|
||||
}
|
||||
|
||||
/// Returns the client settings for this workspace.
|
||||
pub fn settings(&self) -> Option<&ClientSettings> {
|
||||
self.settings.as_ref()
|
||||
}
|
||||
|
||||
/// Returns true if this is the default workspace.
|
||||
pub fn is_default(&self) -> bool {
|
||||
self.is_default
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
@@ -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 {
|
||||
@@ -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 {
|
||||
@@ -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}");
|
||||
@@ -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)
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ use lsp_types::{
|
||||
Position, Range, TextDocumentContentChangeEvent, VersionedTextDocumentIdentifier,
|
||||
};
|
||||
use ruff_notebook::SourceValue;
|
||||
use ruff_server::ClientSettings;
|
||||
use ruff_server::{ClientSettings, Workspaces};
|
||||
|
||||
const SUPER_RESOLUTION_OVERVIEW_PATH: &str =
|
||||
"./resources/test/fixtures/tensorflow_test_notebook.ipynb";
|
||||
@@ -32,10 +32,10 @@ fn super_resolution_overview() {
|
||||
&ClientCapabilities::default(),
|
||||
ruff_server::PositionEncoding::UTF16,
|
||||
ClientSettings::default(),
|
||||
vec![(
|
||||
&Workspaces(vec![(
|
||||
lsp_types::Url::from_file_path(file_path.parent().unwrap()).unwrap(),
|
||||
ClientSettings::default(),
|
||||
)],
|
||||
)]),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user