mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-18 16:20:22 +00:00
Rename Red Knot (#17820)
This commit is contained in:
parent
e6a798b962
commit
b51c4f82ea
1564 changed files with 1598 additions and 1578 deletions
18
crates/ty_server/src/server/api/diagnostics.rs
Normal file
18
crates/ty_server/src/server/api/diagnostics.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
use lsp_server::ErrorCode;
|
||||
use lsp_types::{notification::PublishDiagnostics, PublishDiagnosticsParams, Url};
|
||||
|
||||
use crate::server::client::Notifier;
|
||||
use crate::server::Result;
|
||||
|
||||
use super::LSPResult;
|
||||
|
||||
pub(super) fn clear_diagnostics(uri: &Url, notifier: &Notifier) -> Result<()> {
|
||||
notifier
|
||||
.notify::<PublishDiagnostics>(PublishDiagnosticsParams {
|
||||
uri: uri.clone(),
|
||||
diagnostics: vec![],
|
||||
version: None,
|
||||
})
|
||||
.with_failure_code(ErrorCode::InternalError)?;
|
||||
Ok(())
|
||||
}
|
11
crates/ty_server/src/server/api/notifications.rs
Normal file
11
crates/ty_server/src/server/api/notifications.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
mod did_change;
|
||||
mod did_close;
|
||||
mod did_close_notebook;
|
||||
mod did_open;
|
||||
mod did_open_notebook;
|
||||
|
||||
pub(super) use did_change::DidChangeTextDocumentHandler;
|
||||
pub(super) use did_close::DidCloseTextDocumentHandler;
|
||||
pub(super) use did_close_notebook::DidCloseNotebookHandler;
|
||||
pub(super) use did_open::DidOpenTextDocumentHandler;
|
||||
pub(super) use did_open_notebook::DidOpenNotebookHandler;
|
55
crates/ty_server/src/server/api/notifications/did_change.rs
Normal file
55
crates/ty_server/src/server/api/notifications/did_change.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
use lsp_server::ErrorCode;
|
||||
use lsp_types::notification::DidChangeTextDocument;
|
||||
use lsp_types::DidChangeTextDocumentParams;
|
||||
|
||||
use ty_project::watch::ChangeEvent;
|
||||
|
||||
use crate::server::api::traits::{NotificationHandler, SyncNotificationHandler};
|
||||
use crate::server::api::LSPResult;
|
||||
use crate::server::client::{Notifier, Requester};
|
||||
use crate::server::Result;
|
||||
use crate::session::Session;
|
||||
use crate::system::{url_to_any_system_path, AnySystemPath};
|
||||
|
||||
pub(crate) struct DidChangeTextDocumentHandler;
|
||||
|
||||
impl NotificationHandler for DidChangeTextDocumentHandler {
|
||||
type NotificationType = DidChangeTextDocument;
|
||||
}
|
||||
|
||||
impl SyncNotificationHandler for DidChangeTextDocumentHandler {
|
||||
fn run(
|
||||
session: &mut Session,
|
||||
_notifier: Notifier,
|
||||
_requester: &mut Requester,
|
||||
params: DidChangeTextDocumentParams,
|
||||
) -> Result<()> {
|
||||
let Ok(path) = url_to_any_system_path(¶ms.text_document.uri) else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let key = session.key_from_url(params.text_document.uri);
|
||||
|
||||
session
|
||||
.update_text_document(&key, params.content_changes, params.text_document.version)
|
||||
.with_failure_code(ErrorCode::InternalError)?;
|
||||
|
||||
match path {
|
||||
AnySystemPath::System(path) => {
|
||||
let db = match session.project_db_for_path_mut(path.as_std_path()) {
|
||||
Some(db) => db,
|
||||
None => session.default_project_db_mut(),
|
||||
};
|
||||
db.apply_changes(vec![ChangeEvent::file_content_changed(path)], None);
|
||||
}
|
||||
AnySystemPath::SystemVirtual(virtual_path) => {
|
||||
let db = session.default_project_db_mut();
|
||||
db.apply_changes(vec![ChangeEvent::ChangedVirtual(virtual_path)], None);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(dhruvmanila): Publish diagnostics if the client doesn't support pull diagnostics
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
45
crates/ty_server/src/server/api/notifications/did_close.rs
Normal file
45
crates/ty_server/src/server/api/notifications/did_close.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use lsp_server::ErrorCode;
|
||||
use lsp_types::notification::DidCloseTextDocument;
|
||||
use lsp_types::DidCloseTextDocumentParams;
|
||||
use ty_project::watch::ChangeEvent;
|
||||
|
||||
use crate::server::api::diagnostics::clear_diagnostics;
|
||||
use crate::server::api::traits::{NotificationHandler, SyncNotificationHandler};
|
||||
use crate::server::api::LSPResult;
|
||||
use crate::server::client::{Notifier, Requester};
|
||||
use crate::server::Result;
|
||||
use crate::session::Session;
|
||||
use crate::system::{url_to_any_system_path, AnySystemPath};
|
||||
|
||||
pub(crate) struct DidCloseTextDocumentHandler;
|
||||
|
||||
impl NotificationHandler for DidCloseTextDocumentHandler {
|
||||
type NotificationType = DidCloseTextDocument;
|
||||
}
|
||||
|
||||
impl SyncNotificationHandler for DidCloseTextDocumentHandler {
|
||||
fn run(
|
||||
session: &mut Session,
|
||||
notifier: Notifier,
|
||||
_requester: &mut Requester,
|
||||
params: DidCloseTextDocumentParams,
|
||||
) -> Result<()> {
|
||||
let Ok(path) = url_to_any_system_path(¶ms.text_document.uri) else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let key = session.key_from_url(params.text_document.uri);
|
||||
session
|
||||
.close_document(&key)
|
||||
.with_failure_code(ErrorCode::InternalError)?;
|
||||
|
||||
if let AnySystemPath::SystemVirtual(virtual_path) = path {
|
||||
let db = session.default_project_db_mut();
|
||||
db.apply_changes(vec![ChangeEvent::DeletedVirtual(virtual_path)], None);
|
||||
}
|
||||
|
||||
clear_diagnostics(key.url(), ¬ifier)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
use lsp_types::notification::DidCloseNotebookDocument;
|
||||
use lsp_types::DidCloseNotebookDocumentParams;
|
||||
|
||||
use ty_project::watch::ChangeEvent;
|
||||
|
||||
use crate::server::api::traits::{NotificationHandler, SyncNotificationHandler};
|
||||
use crate::server::api::LSPResult;
|
||||
use crate::server::client::{Notifier, Requester};
|
||||
use crate::server::Result;
|
||||
use crate::session::Session;
|
||||
use crate::system::{url_to_any_system_path, AnySystemPath};
|
||||
|
||||
pub(crate) struct DidCloseNotebookHandler;
|
||||
|
||||
impl NotificationHandler for DidCloseNotebookHandler {
|
||||
type NotificationType = DidCloseNotebookDocument;
|
||||
}
|
||||
|
||||
impl SyncNotificationHandler for DidCloseNotebookHandler {
|
||||
fn run(
|
||||
session: &mut Session,
|
||||
_notifier: Notifier,
|
||||
_requester: &mut Requester,
|
||||
params: DidCloseNotebookDocumentParams,
|
||||
) -> Result<()> {
|
||||
let Ok(path) = url_to_any_system_path(¶ms.notebook_document.uri) else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let key = session.key_from_url(params.notebook_document.uri);
|
||||
session
|
||||
.close_document(&key)
|
||||
.with_failure_code(lsp_server::ErrorCode::InternalError)?;
|
||||
|
||||
if let AnySystemPath::SystemVirtual(virtual_path) = path {
|
||||
let db = session.default_project_db_mut();
|
||||
db.apply_changes(vec![ChangeEvent::DeletedVirtual(virtual_path)], None);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
60
crates/ty_server/src/server/api/notifications/did_open.rs
Normal file
60
crates/ty_server/src/server/api/notifications/did_open.rs
Normal file
|
@ -0,0 +1,60 @@
|
|||
use lsp_types::notification::DidOpenTextDocument;
|
||||
use lsp_types::{DidOpenTextDocumentParams, TextDocumentItem};
|
||||
|
||||
use ruff_db::Db;
|
||||
use ty_project::watch::ChangeEvent;
|
||||
|
||||
use crate::server::api::traits::{NotificationHandler, SyncNotificationHandler};
|
||||
use crate::server::client::{Notifier, Requester};
|
||||
use crate::server::Result;
|
||||
use crate::session::Session;
|
||||
use crate::system::{url_to_any_system_path, AnySystemPath};
|
||||
use crate::TextDocument;
|
||||
|
||||
pub(crate) struct DidOpenTextDocumentHandler;
|
||||
|
||||
impl NotificationHandler for DidOpenTextDocumentHandler {
|
||||
type NotificationType = DidOpenTextDocument;
|
||||
}
|
||||
|
||||
impl SyncNotificationHandler for DidOpenTextDocumentHandler {
|
||||
fn run(
|
||||
session: &mut Session,
|
||||
_notifier: Notifier,
|
||||
_requester: &mut Requester,
|
||||
DidOpenTextDocumentParams {
|
||||
text_document:
|
||||
TextDocumentItem {
|
||||
uri,
|
||||
text,
|
||||
version,
|
||||
language_id,
|
||||
},
|
||||
}: DidOpenTextDocumentParams,
|
||||
) -> Result<()> {
|
||||
let Ok(path) = url_to_any_system_path(&uri) else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let document = TextDocument::new(text, version).with_language_id(&language_id);
|
||||
session.open_text_document(uri, document);
|
||||
|
||||
match path {
|
||||
AnySystemPath::System(path) => {
|
||||
let db = match session.project_db_for_path_mut(path.as_std_path()) {
|
||||
Some(db) => db,
|
||||
None => session.default_project_db_mut(),
|
||||
};
|
||||
db.apply_changes(vec![ChangeEvent::Opened(path)], None);
|
||||
}
|
||||
AnySystemPath::SystemVirtual(virtual_path) => {
|
||||
let db = session.default_project_db_mut();
|
||||
db.files().virtual_file(db, &virtual_path);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(dhruvmanila): Publish diagnostics if the client doesn't support pull diagnostics
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
use lsp_server::ErrorCode;
|
||||
use lsp_types::notification::DidOpenNotebookDocument;
|
||||
use lsp_types::DidOpenNotebookDocumentParams;
|
||||
|
||||
use ruff_db::Db;
|
||||
use ty_project::watch::ChangeEvent;
|
||||
|
||||
use crate::document::NotebookDocument;
|
||||
use crate::server::api::traits::{NotificationHandler, SyncNotificationHandler};
|
||||
use crate::server::api::LSPResult;
|
||||
use crate::server::client::{Notifier, Requester};
|
||||
use crate::server::Result;
|
||||
use crate::session::Session;
|
||||
use crate::system::{url_to_any_system_path, AnySystemPath};
|
||||
|
||||
pub(crate) struct DidOpenNotebookHandler;
|
||||
|
||||
impl NotificationHandler for DidOpenNotebookHandler {
|
||||
type NotificationType = DidOpenNotebookDocument;
|
||||
}
|
||||
|
||||
impl SyncNotificationHandler for DidOpenNotebookHandler {
|
||||
fn run(
|
||||
session: &mut Session,
|
||||
_notifier: Notifier,
|
||||
_requester: &mut Requester,
|
||||
params: DidOpenNotebookDocumentParams,
|
||||
) -> Result<()> {
|
||||
let Ok(path) = url_to_any_system_path(¶ms.notebook_document.uri) else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let notebook = NotebookDocument::new(
|
||||
params.notebook_document.version,
|
||||
params.notebook_document.cells,
|
||||
params.notebook_document.metadata.unwrap_or_default(),
|
||||
params.cell_text_documents,
|
||||
)
|
||||
.with_failure_code(ErrorCode::InternalError)?;
|
||||
session.open_notebook_document(params.notebook_document.uri, notebook);
|
||||
|
||||
match path {
|
||||
AnySystemPath::System(path) => {
|
||||
let db = match session.project_db_for_path_mut(path.as_std_path()) {
|
||||
Some(db) => db,
|
||||
None => session.default_project_db_mut(),
|
||||
};
|
||||
db.apply_changes(vec![ChangeEvent::Opened(path)], None);
|
||||
}
|
||||
AnySystemPath::SystemVirtual(virtual_path) => {
|
||||
let db = session.default_project_db_mut();
|
||||
db.files().virtual_file(db, &virtual_path);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(dhruvmanila): Publish diagnostics if the client doesn't support pull diagnostics
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
11
crates/ty_server/src/server/api/requests.rs
Normal file
11
crates/ty_server/src/server/api/requests.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
mod completion;
|
||||
mod diagnostic;
|
||||
mod goto_type_definition;
|
||||
mod hover;
|
||||
mod inlay_hints;
|
||||
|
||||
pub(super) use completion::CompletionRequestHandler;
|
||||
pub(super) use diagnostic::DocumentDiagnosticRequestHandler;
|
||||
pub(super) use goto_type_definition::GotoTypeDefinitionRequestHandler;
|
||||
pub(super) use hover::HoverRequestHandler;
|
||||
pub(super) use inlay_hints::InlayHintRequestHandler;
|
58
crates/ty_server/src/server/api/requests/completion.rs
Normal file
58
crates/ty_server/src/server/api/requests/completion.rs
Normal file
|
@ -0,0 +1,58 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use lsp_types::request::Completion;
|
||||
use lsp_types::{CompletionItem, CompletionParams, CompletionResponse, Url};
|
||||
use ruff_db::source::{line_index, source_text};
|
||||
use ty_ide::completion;
|
||||
use ty_project::ProjectDatabase;
|
||||
|
||||
use crate::document::PositionExt;
|
||||
use crate::server::api::traits::{BackgroundDocumentRequestHandler, RequestHandler};
|
||||
use crate::server::client::Notifier;
|
||||
use crate::DocumentSnapshot;
|
||||
|
||||
pub(crate) struct CompletionRequestHandler;
|
||||
|
||||
impl RequestHandler for CompletionRequestHandler {
|
||||
type RequestType = Completion;
|
||||
}
|
||||
|
||||
impl BackgroundDocumentRequestHandler for CompletionRequestHandler {
|
||||
fn document_url(params: &CompletionParams) -> Cow<Url> {
|
||||
Cow::Borrowed(¶ms.text_document_position.text_document.uri)
|
||||
}
|
||||
|
||||
fn run_with_snapshot(
|
||||
snapshot: DocumentSnapshot,
|
||||
db: ProjectDatabase,
|
||||
_notifier: Notifier,
|
||||
params: CompletionParams,
|
||||
) -> crate::server::Result<Option<CompletionResponse>> {
|
||||
let Some(file) = snapshot.file(&db) else {
|
||||
tracing::debug!("Failed to resolve file for {:?}", params);
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let source = source_text(&db, file);
|
||||
let line_index = line_index(&db, file);
|
||||
let offset = params.text_document_position.position.to_text_size(
|
||||
&source,
|
||||
&line_index,
|
||||
snapshot.encoding(),
|
||||
);
|
||||
let completions = completion(&db, file, offset);
|
||||
if completions.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let items: Vec<CompletionItem> = completions
|
||||
.into_iter()
|
||||
.map(|comp| CompletionItem {
|
||||
label: comp.label,
|
||||
..Default::default()
|
||||
})
|
||||
.collect();
|
||||
let response = CompletionResponse::Array(items);
|
||||
Ok(Some(response))
|
||||
}
|
||||
}
|
106
crates/ty_server/src/server/api/requests/diagnostic.rs
Normal file
106
crates/ty_server/src/server/api/requests/diagnostic.rs
Normal file
|
@ -0,0 +1,106 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use lsp_types::request::DocumentDiagnosticRequest;
|
||||
use lsp_types::{
|
||||
Diagnostic, DiagnosticSeverity, DocumentDiagnosticParams, DocumentDiagnosticReport,
|
||||
DocumentDiagnosticReportResult, FullDocumentDiagnosticReport, NumberOrString, Range,
|
||||
RelatedFullDocumentDiagnosticReport, Url,
|
||||
};
|
||||
|
||||
use crate::document::ToRangeExt;
|
||||
use crate::server::api::traits::{BackgroundDocumentRequestHandler, RequestHandler};
|
||||
use crate::server::{client::Notifier, Result};
|
||||
use crate::session::DocumentSnapshot;
|
||||
use ruff_db::diagnostic::Severity;
|
||||
use ruff_db::source::{line_index, source_text};
|
||||
use ty_project::{Db, ProjectDatabase};
|
||||
|
||||
pub(crate) struct DocumentDiagnosticRequestHandler;
|
||||
|
||||
impl RequestHandler for DocumentDiagnosticRequestHandler {
|
||||
type RequestType = DocumentDiagnosticRequest;
|
||||
}
|
||||
|
||||
impl BackgroundDocumentRequestHandler for DocumentDiagnosticRequestHandler {
|
||||
fn document_url(params: &DocumentDiagnosticParams) -> Cow<Url> {
|
||||
Cow::Borrowed(¶ms.text_document.uri)
|
||||
}
|
||||
|
||||
fn run_with_snapshot(
|
||||
snapshot: DocumentSnapshot,
|
||||
db: ProjectDatabase,
|
||||
_notifier: Notifier,
|
||||
_params: DocumentDiagnosticParams,
|
||||
) -> Result<DocumentDiagnosticReportResult> {
|
||||
let diagnostics = compute_diagnostics(&snapshot, &db);
|
||||
|
||||
Ok(DocumentDiagnosticReportResult::Report(
|
||||
DocumentDiagnosticReport::Full(RelatedFullDocumentDiagnosticReport {
|
||||
related_documents: None,
|
||||
full_document_diagnostic_report: FullDocumentDiagnosticReport {
|
||||
result_id: None,
|
||||
items: diagnostics,
|
||||
},
|
||||
}),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_diagnostics(snapshot: &DocumentSnapshot, db: &ProjectDatabase) -> Vec<Diagnostic> {
|
||||
let Some(file) = snapshot.file(db) else {
|
||||
tracing::info!(
|
||||
"No file found for snapshot for `{}`",
|
||||
snapshot.query().file_url()
|
||||
);
|
||||
return vec![];
|
||||
};
|
||||
|
||||
let diagnostics = match db.check_file(file) {
|
||||
Ok(diagnostics) => diagnostics,
|
||||
Err(cancelled) => {
|
||||
tracing::info!("Diagnostics computation {cancelled}");
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
|
||||
diagnostics
|
||||
.as_slice()
|
||||
.iter()
|
||||
.map(|message| to_lsp_diagnostic(db, message, snapshot.encoding()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn to_lsp_diagnostic(
|
||||
db: &dyn Db,
|
||||
diagnostic: &ruff_db::diagnostic::Diagnostic,
|
||||
encoding: crate::PositionEncoding,
|
||||
) -> Diagnostic {
|
||||
let range = if let Some(span) = diagnostic.primary_span() {
|
||||
let index = line_index(db.upcast(), span.file());
|
||||
let source = source_text(db.upcast(), span.file());
|
||||
|
||||
span.range()
|
||||
.map(|range| range.to_lsp_range(&source, &index, encoding))
|
||||
.unwrap_or_default()
|
||||
} else {
|
||||
Range::default()
|
||||
};
|
||||
|
||||
let severity = match diagnostic.severity() {
|
||||
Severity::Info => DiagnosticSeverity::INFORMATION,
|
||||
Severity::Warning => DiagnosticSeverity::WARNING,
|
||||
Severity::Error | Severity::Fatal => DiagnosticSeverity::ERROR,
|
||||
};
|
||||
|
||||
Diagnostic {
|
||||
range,
|
||||
severity: Some(severity),
|
||||
tags: None,
|
||||
code: Some(NumberOrString::String(diagnostic.id().to_string())),
|
||||
code_description: None,
|
||||
source: Some("ty".into()),
|
||||
message: diagnostic.concise_message().to_string(),
|
||||
related_information: None,
|
||||
data: None,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use lsp_types::request::{GotoTypeDefinition, GotoTypeDefinitionParams};
|
||||
use lsp_types::{GotoDefinitionResponse, Url};
|
||||
use ruff_db::source::{line_index, source_text};
|
||||
use ty_ide::goto_type_definition;
|
||||
use ty_project::ProjectDatabase;
|
||||
|
||||
use crate::document::{PositionExt, ToLink};
|
||||
use crate::server::api::traits::{BackgroundDocumentRequestHandler, RequestHandler};
|
||||
use crate::server::client::Notifier;
|
||||
use crate::DocumentSnapshot;
|
||||
|
||||
pub(crate) struct GotoTypeDefinitionRequestHandler;
|
||||
|
||||
impl RequestHandler for GotoTypeDefinitionRequestHandler {
|
||||
type RequestType = GotoTypeDefinition;
|
||||
}
|
||||
|
||||
impl BackgroundDocumentRequestHandler for GotoTypeDefinitionRequestHandler {
|
||||
fn document_url(params: &GotoTypeDefinitionParams) -> Cow<Url> {
|
||||
Cow::Borrowed(¶ms.text_document_position_params.text_document.uri)
|
||||
}
|
||||
|
||||
fn run_with_snapshot(
|
||||
snapshot: DocumentSnapshot,
|
||||
db: ProjectDatabase,
|
||||
_notifier: Notifier,
|
||||
params: GotoTypeDefinitionParams,
|
||||
) -> crate::server::Result<Option<GotoDefinitionResponse>> {
|
||||
let Some(file) = snapshot.file(&db) else {
|
||||
tracing::debug!("Failed to resolve file for {:?}", params);
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let source = source_text(&db, file);
|
||||
let line_index = line_index(&db, file);
|
||||
let offset = params.text_document_position_params.position.to_text_size(
|
||||
&source,
|
||||
&line_index,
|
||||
snapshot.encoding(),
|
||||
);
|
||||
|
||||
let Some(ranged) = goto_type_definition(&db, file, offset) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
if snapshot
|
||||
.resolved_client_capabilities()
|
||||
.type_definition_link_support
|
||||
{
|
||||
let src = Some(ranged.range);
|
||||
let links: Vec<_> = ranged
|
||||
.into_iter()
|
||||
.filter_map(|target| target.to_link(&db, src, snapshot.encoding()))
|
||||
.collect();
|
||||
|
||||
Ok(Some(GotoDefinitionResponse::Link(links)))
|
||||
} else {
|
||||
let locations: Vec<_> = ranged
|
||||
.into_iter()
|
||||
.filter_map(|target| target.to_location(&db, snapshot.encoding()))
|
||||
.collect();
|
||||
|
||||
Ok(Some(GotoDefinitionResponse::Array(locations)))
|
||||
}
|
||||
}
|
||||
}
|
71
crates/ty_server/src/server/api/requests/hover.rs
Normal file
71
crates/ty_server/src/server/api/requests/hover.rs
Normal file
|
@ -0,0 +1,71 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use crate::document::{PositionExt, ToRangeExt};
|
||||
use crate::server::api::traits::{BackgroundDocumentRequestHandler, RequestHandler};
|
||||
use crate::server::client::Notifier;
|
||||
use crate::DocumentSnapshot;
|
||||
use lsp_types::request::HoverRequest;
|
||||
use lsp_types::{HoverContents, HoverParams, MarkupContent, Url};
|
||||
use ruff_db::source::{line_index, source_text};
|
||||
use ruff_text_size::Ranged;
|
||||
use ty_ide::{hover, MarkupKind};
|
||||
use ty_project::ProjectDatabase;
|
||||
|
||||
pub(crate) struct HoverRequestHandler;
|
||||
|
||||
impl RequestHandler for HoverRequestHandler {
|
||||
type RequestType = HoverRequest;
|
||||
}
|
||||
|
||||
impl BackgroundDocumentRequestHandler for HoverRequestHandler {
|
||||
fn document_url(params: &HoverParams) -> Cow<Url> {
|
||||
Cow::Borrowed(¶ms.text_document_position_params.text_document.uri)
|
||||
}
|
||||
|
||||
fn run_with_snapshot(
|
||||
snapshot: DocumentSnapshot,
|
||||
db: ProjectDatabase,
|
||||
_notifier: Notifier,
|
||||
params: HoverParams,
|
||||
) -> crate::server::Result<Option<lsp_types::Hover>> {
|
||||
let Some(file) = snapshot.file(&db) else {
|
||||
tracing::debug!("Failed to resolve file for {:?}", params);
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let source = source_text(&db, file);
|
||||
let line_index = line_index(&db, file);
|
||||
let offset = params.text_document_position_params.position.to_text_size(
|
||||
&source,
|
||||
&line_index,
|
||||
snapshot.encoding(),
|
||||
);
|
||||
|
||||
let Some(range_info) = hover(&db, file, offset) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let (markup_kind, lsp_markup_kind) = if snapshot
|
||||
.resolved_client_capabilities()
|
||||
.hover_prefer_markdown
|
||||
{
|
||||
(MarkupKind::Markdown, lsp_types::MarkupKind::Markdown)
|
||||
} else {
|
||||
(MarkupKind::PlainText, lsp_types::MarkupKind::PlainText)
|
||||
};
|
||||
|
||||
let contents = range_info.display(&db, markup_kind).to_string();
|
||||
|
||||
Ok(Some(lsp_types::Hover {
|
||||
contents: HoverContents::Markup(MarkupContent {
|
||||
kind: lsp_markup_kind,
|
||||
value: contents,
|
||||
}),
|
||||
range: Some(range_info.file_range().range().to_lsp_range(
|
||||
&source,
|
||||
&line_index,
|
||||
snapshot.encoding(),
|
||||
)),
|
||||
}))
|
||||
}
|
||||
}
|
62
crates/ty_server/src/server/api/requests/inlay_hints.rs
Normal file
62
crates/ty_server/src/server/api/requests/inlay_hints.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use crate::document::{RangeExt, TextSizeExt};
|
||||
use crate::server::api::traits::{BackgroundDocumentRequestHandler, RequestHandler};
|
||||
use crate::server::client::Notifier;
|
||||
use crate::DocumentSnapshot;
|
||||
use lsp_types::request::InlayHintRequest;
|
||||
use lsp_types::{InlayHintParams, Url};
|
||||
use ruff_db::source::{line_index, source_text};
|
||||
use ty_ide::inlay_hints;
|
||||
use ty_project::ProjectDatabase;
|
||||
|
||||
pub(crate) struct InlayHintRequestHandler;
|
||||
|
||||
impl RequestHandler for InlayHintRequestHandler {
|
||||
type RequestType = InlayHintRequest;
|
||||
}
|
||||
|
||||
impl BackgroundDocumentRequestHandler for InlayHintRequestHandler {
|
||||
fn document_url(params: &InlayHintParams) -> Cow<Url> {
|
||||
Cow::Borrowed(¶ms.text_document.uri)
|
||||
}
|
||||
|
||||
fn run_with_snapshot(
|
||||
snapshot: DocumentSnapshot,
|
||||
db: ProjectDatabase,
|
||||
_notifier: Notifier,
|
||||
params: InlayHintParams,
|
||||
) -> crate::server::Result<Option<Vec<lsp_types::InlayHint>>> {
|
||||
let Some(file) = snapshot.file(&db) else {
|
||||
tracing::debug!("Failed to resolve file for {:?}", params);
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let index = line_index(&db, file);
|
||||
let source = source_text(&db, file);
|
||||
|
||||
let range = params
|
||||
.range
|
||||
.to_text_range(&source, &index, snapshot.encoding());
|
||||
|
||||
let inlay_hints = inlay_hints(&db, file, range);
|
||||
|
||||
let inlay_hints = inlay_hints
|
||||
.into_iter()
|
||||
.map(|hint| lsp_types::InlayHint {
|
||||
position: hint
|
||||
.position
|
||||
.to_position(&source, &index, snapshot.encoding()),
|
||||
label: lsp_types::InlayHintLabel::String(hint.display(&db).to_string()),
|
||||
kind: Some(lsp_types::InlayHintKind::TYPE),
|
||||
tooltip: None,
|
||||
padding_left: None,
|
||||
padding_right: None,
|
||||
data: None,
|
||||
text_edits: None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(Some(inlay_hints))
|
||||
}
|
||||
}
|
78
crates/ty_server/src/server/api/traits.rs
Normal file
78
crates/ty_server/src/server/api/traits.rs
Normal file
|
@ -0,0 +1,78 @@
|
|||
//! A stateful LSP implementation that calls into the Ruff API.
|
||||
|
||||
use crate::server::client::{Notifier, Requester};
|
||||
use crate::session::{DocumentSnapshot, Session};
|
||||
|
||||
use lsp_types::notification::Notification as LSPNotification;
|
||||
use lsp_types::request::Request;
|
||||
use ty_project::ProjectDatabase;
|
||||
|
||||
/// A supertrait for any server request handler.
|
||||
pub(super) trait RequestHandler {
|
||||
type RequestType: Request;
|
||||
const METHOD: &'static str = <<Self as RequestHandler>::RequestType as Request>::METHOD;
|
||||
}
|
||||
|
||||
/// A request handler that needs mutable access to the session.
|
||||
/// This will block the main message receiver loop, meaning that no
|
||||
/// incoming requests or notifications will be handled while `run` is
|
||||
/// executing. Try to avoid doing any I/O or long-running computations.
|
||||
#[expect(dead_code)]
|
||||
pub(super) trait SyncRequestHandler: RequestHandler {
|
||||
fn run(
|
||||
session: &mut Session,
|
||||
notifier: Notifier,
|
||||
requester: &mut Requester,
|
||||
params: <<Self as RequestHandler>::RequestType as Request>::Params,
|
||||
) -> super::Result<<<Self as RequestHandler>::RequestType as Request>::Result>;
|
||||
}
|
||||
|
||||
/// A request handler that can be run on a background thread.
|
||||
pub(super) trait BackgroundDocumentRequestHandler: RequestHandler {
|
||||
fn document_url(
|
||||
params: &<<Self as RequestHandler>::RequestType as Request>::Params,
|
||||
) -> std::borrow::Cow<lsp_types::Url>;
|
||||
|
||||
fn run_with_snapshot(
|
||||
snapshot: DocumentSnapshot,
|
||||
db: ProjectDatabase,
|
||||
notifier: Notifier,
|
||||
params: <<Self as RequestHandler>::RequestType as Request>::Params,
|
||||
) -> super::Result<<<Self as RequestHandler>::RequestType as Request>::Result>;
|
||||
}
|
||||
|
||||
/// A supertrait for any server notification handler.
|
||||
pub(super) trait NotificationHandler {
|
||||
type NotificationType: LSPNotification;
|
||||
const METHOD: &'static str =
|
||||
<<Self as NotificationHandler>::NotificationType as LSPNotification>::METHOD;
|
||||
}
|
||||
|
||||
/// A notification handler that needs mutable access to the session.
|
||||
/// This will block the main message receiver loop, meaning that no
|
||||
/// incoming requests or notifications will be handled while `run` is
|
||||
/// executing. Try to avoid doing any I/O or long-running computations.
|
||||
pub(super) trait SyncNotificationHandler: NotificationHandler {
|
||||
fn run(
|
||||
session: &mut Session,
|
||||
notifier: Notifier,
|
||||
requester: &mut Requester,
|
||||
params: <<Self as NotificationHandler>::NotificationType as LSPNotification>::Params,
|
||||
) -> super::Result<()>;
|
||||
}
|
||||
|
||||
/// A notification handler that can be run on a background thread.
|
||||
pub(super) trait BackgroundDocumentNotificationHandler: NotificationHandler {
|
||||
/// `document_url` can be implemented automatically with
|
||||
/// `define_document_url!(params: &<YourParameterType>)` in the trait
|
||||
/// implementation.
|
||||
fn document_url(
|
||||
params: &<<Self as NotificationHandler>::NotificationType as LSPNotification>::Params,
|
||||
) -> std::borrow::Cow<lsp_types::Url>;
|
||||
|
||||
fn run_with_snapshot(
|
||||
snapshot: DocumentSnapshot,
|
||||
notifier: Notifier,
|
||||
params: <<Self as NotificationHandler>::NotificationType as LSPNotification>::Params,
|
||||
) -> super::Result<()>;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue