Skip to content

Commit f335a4d

Browse files
committed
[ty] Add python.ty.disableLanguageServices config
1 parent 32403df commit f335a4d

File tree

7 files changed

+116
-3
lines changed

7 files changed

+116
-3
lines changed

crates/ty_server/src/server/api/requests/completion.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ impl BackgroundDocumentRequestHandler for CompletionRequestHandler {
2828
_notifier: Notifier,
2929
params: CompletionParams,
3030
) -> crate::server::Result<Option<CompletionResponse>> {
31+
if snapshot.client_settings().is_language_services_disabled() {
32+
return Ok(None);
33+
}
34+
3135
let Some(file) = snapshot.file(db) else {
3236
tracing::debug!("Failed to resolve file for {:?}", params);
3337
return Ok(None);

crates/ty_server/src/server/api/requests/goto_type_definition.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ impl BackgroundDocumentRequestHandler for GotoTypeDefinitionRequestHandler {
2828
_notifier: Notifier,
2929
params: GotoTypeDefinitionParams,
3030
) -> crate::server::Result<Option<GotoDefinitionResponse>> {
31+
if snapshot.client_settings().is_language_services_disabled() {
32+
return Ok(None);
33+
}
34+
3135
let Some(file) = snapshot.file(db) else {
3236
tracing::debug!("Failed to resolve file for {:?}", params);
3337
return Ok(None);

crates/ty_server/src/server/api/requests/hover.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ impl BackgroundDocumentRequestHandler for HoverRequestHandler {
2828
_notifier: Notifier,
2929
params: HoverParams,
3030
) -> crate::server::Result<Option<lsp_types::Hover>> {
31+
if snapshot.client_settings().is_language_services_disabled() {
32+
return Ok(None);
33+
}
34+
3135
let Some(file) = snapshot.file(db) else {
3236
tracing::debug!("Failed to resolve file for {:?}", params);
3337
return Ok(None);

crates/ty_server/src/server/api/requests/inlay_hints.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ impl BackgroundDocumentRequestHandler for InlayHintRequestHandler {
2727
_notifier: Notifier,
2828
params: InlayHintParams,
2929
) -> crate::server::Result<Option<Vec<lsp_types::InlayHint>>> {
30+
if snapshot.client_settings().is_language_services_disabled() {
31+
return Ok(None);
32+
}
33+
3034
let Some(file) = snapshot.file(db) else {
3135
tracing::debug!("Failed to resolve file for {:?}", params);
3236
return Ok(None);

crates/ty_server/src/session.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use lsp_types::{ClientCapabilities, TextDocumentContentChangeEvent, Url};
1111
use ruff_db::Db;
1212
use ruff_db::files::{File, system_path_to_file};
1313
use ruff_db::system::SystemPath;
14+
use settings::ResolvedClientSettings;
1415
use ty_project::{ProjectDatabase, ProjectMetadata};
1516

1617
use crate::document::{DocumentKey, DocumentVersion, NotebookDocument};
@@ -136,6 +137,7 @@ impl Session {
136137
let key = self.key_from_url(url);
137138
Some(DocumentSnapshot {
138139
resolved_client_capabilities: self.resolved_client_capabilities.clone(),
140+
client_settings: self.index().client_settings(),
139141
document_ref: self.index().make_document_ref(key)?,
140142
position_encoding: self.position_encoding,
141143
})
@@ -260,6 +262,7 @@ impl Drop for MutIndexGuard<'_> {
260262
#[derive(Debug)]
261263
pub struct DocumentSnapshot {
262264
resolved_client_capabilities: Arc<ResolvedClientCapabilities>,
265+
client_settings: ResolvedClientSettings,
263266
document_ref: index::DocumentQuery,
264267
position_encoding: PositionEncoding,
265268
}
@@ -269,14 +272,18 @@ impl DocumentSnapshot {
269272
&self.resolved_client_capabilities
270273
}
271274

272-
pub fn query(&self) -> &index::DocumentQuery {
275+
pub(crate) fn query(&self) -> &index::DocumentQuery {
273276
&self.document_ref
274277
}
275278

276279
pub(crate) fn encoding(&self) -> PositionEncoding {
277280
self.position_encoding
278281
}
279282

283+
pub(crate) fn client_settings(&self) -> &ResolvedClientSettings {
284+
&self.client_settings
285+
}
286+
280287
pub(crate) fn file(&self, db: &dyn Db) -> Option<File> {
281288
match url_to_any_system_path(self.document_ref.file_url()).ok()? {
282289
AnySystemPath::System(path) => system_path_to_file(db, path).ok(),

crates/ty_server/src/session/index.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::{
1010
};
1111

1212
use super::ClientSettings;
13+
use super::settings::ResolvedClientSettings;
1314

1415
/// Stores and tracks all open documents in a session, along with their associated settings.
1516
#[derive(Default, Debug)]
@@ -21,7 +22,6 @@ pub(crate) struct Index {
2122
notebook_cells: FxHashMap<Url, Url>,
2223

2324
/// Global settings provided by the client.
24-
#[expect(dead_code)]
2525
global_settings: ClientSettings,
2626
}
2727

@@ -165,6 +165,10 @@ impl Index {
165165
Ok(())
166166
}
167167

168+
pub(crate) fn client_settings(&self) -> ResolvedClientSettings {
169+
ResolvedClientSettings::global(&self.global_settings)
170+
}
171+
168172
fn document_controller_for_key(
169173
&mut self,
170174
key: &DocumentKey,

crates/ty_server/src/session/settings.rs

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::path::PathBuf;
1+
use std::{ops::Deref, path::PathBuf};
22

33
use lsp_types::Url;
44
use rustc_hash::FxHashMap;
@@ -7,6 +7,24 @@ use serde::Deserialize;
77
/// Maps a workspace URI to its associated client settings. Used during server initialization.
88
pub(crate) type WorkspaceSettingsMap = FxHashMap<Url, ClientSettings>;
99

10+
// TODO(dhruvmanila): We need to mirror the "python.*" namespace on the server side but ideally it
11+
// would be useful to instead use `workspace/didChangeConfiguration` notification instead. This
12+
// would be then used to get all settings and not just the ones in "python.*".
13+
14+
#[derive(Debug, Deserialize, Default)]
15+
#[cfg_attr(test, derive(PartialEq, Eq))]
16+
#[serde(rename_all = "camelCase")]
17+
struct Python {
18+
ty: Option<Ty>,
19+
}
20+
21+
#[derive(Debug, Deserialize, Default)]
22+
#[cfg_attr(test, derive(PartialEq, Eq))]
23+
#[serde(rename_all = "camelCase")]
24+
struct Ty {
25+
disable_language_services: Option<bool>,
26+
}
27+
1028
#[derive(Debug, Deserialize, Default)]
1129
#[cfg_attr(test, derive(PartialEq, Eq))]
1230
#[serde(rename_all = "camelCase")]
@@ -36,6 +54,11 @@ impl Experimental {
3654
#[serde(rename_all = "camelCase")]
3755
pub struct ClientSettings {
3856
pub(crate) experimental: Option<Experimental>,
57+
58+
/// Settings under the `python.*` namespace in VS Code that are useful for the ty language
59+
/// server.
60+
python: Option<Python>,
61+
3962
// These settings are only needed for tracing, and are only read from the global configuration.
4063
// These will not be in the resolved settings.
4164
#[serde(flatten)]
@@ -133,3 +156,66 @@ impl Default for InitializationOptions {
133156
}
134157
}
135158
}
159+
160+
/// Resolved client settings for a specific document. These settings are meant to be
161+
/// used directly by the server, and are *not* a 1:1 representation with how the client
162+
/// sends them.
163+
#[derive(Clone, Debug)]
164+
#[cfg_attr(test, derive(PartialEq, Eq))]
165+
pub(crate) struct ResolvedClientSettings {
166+
disable_language_services: bool,
167+
}
168+
169+
impl ResolvedClientSettings {
170+
pub(crate) fn is_language_services_disabled(&self) -> bool {
171+
self.disable_language_services
172+
}
173+
174+
/// Resolves global settings only.
175+
pub(super) fn global(global_settings: &ClientSettings) -> Self {
176+
Self::new_impl(&[global_settings])
177+
}
178+
179+
fn new_impl(all_settings: &[&ClientSettings]) -> Self {
180+
Self {
181+
disable_language_services: Self::resolve_or(
182+
all_settings,
183+
|settings| {
184+
settings
185+
.python
186+
.as_ref()?
187+
.ty
188+
.as_ref()?
189+
.disable_language_services
190+
},
191+
false,
192+
),
193+
}
194+
}
195+
196+
/// Attempts to resolve a setting using a list of available client settings as sources.
197+
/// Client settings that come earlier in the list take priority. `default` will be returned
198+
/// if none of the settings specify the requested setting.
199+
///
200+
/// Use [`ResolvedClientSettings::resolve_optional`] if the setting should be optional instead
201+
/// of having a default value.
202+
fn resolve_or<T>(
203+
all_settings: &[&ClientSettings],
204+
get: impl Fn(&ClientSettings) -> Option<T>,
205+
default: T,
206+
) -> T {
207+
Self::resolve_optional(all_settings, get).unwrap_or(default)
208+
}
209+
210+
/// Attempts to resolve a setting using a list of available client settings as sources.
211+
/// Client settings that come earlier in the list take priority. This function is for fields
212+
/// that do not have a default value and should be left unset.
213+
///
214+
/// Use [`ResolvedClientSettings::resolve_or`] for settings that should have default values.
215+
fn resolve_optional<T>(
216+
all_settings: &[&ClientSettings],
217+
get: impl FnMut(&ClientSettings) -> Option<T>,
218+
) -> Option<T> {
219+
all_settings.iter().map(Deref::deref).find_map(get)
220+
}
221+
}

0 commit comments

Comments
 (0)