deps_lsp/handlers/
document_link.rs1use crate::config::DepsConfig;
9use crate::document::{ServerState, ensure_document_loaded};
10use std::sync::Arc;
11use tokio::sync::RwLock;
12use tower_lsp_server::Client;
13use tower_lsp_server::ls_types::{DocumentLink, DocumentLinkParams};
14
15pub async fn handle_document_link(
17 state: Arc<ServerState>,
18 params: DocumentLinkParams,
19 client: Client,
20 config: Arc<RwLock<DepsConfig>>,
21) -> Vec<DocumentLink> {
22 let uri = ¶ms.text_document.uri;
23
24 if !ensure_document_loaded(uri, Arc::clone(&state), client, config).await {
26 tracing::warn!("Could not load document for document link: {:?}", uri);
27 return vec![];
28 }
29
30 let Some((ecosystem, parse_result)) = state
35 .with_document(uri, |doc| {
36 let ecosystem = state.ecosystem_registry.get(doc.ecosystem_id())?;
37 let parse_result = doc.parse_result_arc()?;
38 Some((ecosystem, parse_result))
39 })
40 .flatten()
41 else {
42 return vec![];
43 };
44
45 ecosystem.generate_document_links(parse_result.as_ref(), uri)
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use crate::document::ServerState;
52 use crate::test_utils::test_helpers::create_test_client_and_config;
53 use tower_lsp_server::ls_types::TextDocumentIdentifier;
54
55 #[tokio::test]
56 async fn test_handle_document_link_missing_document() {
57 let state = Arc::new(ServerState::new());
58 let uri = deps_core::test_util::test_uri("/test/requirements.txt");
59 let (client, config) = create_test_client_and_config();
60
61 let params = DocumentLinkParams {
62 text_document: TextDocumentIdentifier { uri },
63 work_done_progress_params: Default::default(),
64 partial_result_params: Default::default(),
65 };
66
67 let result = handle_document_link(state, params, client, config).await;
68 assert!(result.is_empty());
69 }
70
71 #[cfg(feature = "pypi")]
72 mod pypi_tests {
73 use super::*;
74 use crate::document::DocumentState;
75 use deps_core::EcosystemId;
76
77 #[tokio::test]
78 async fn test_handle_document_link_requirements_reference() {
79 let state = Arc::new(ServerState::new());
80 let uri = deps_core::test_util::test_uri("/test/requirements.txt");
81
82 let ecosystem = state.ecosystem_registry.get("pypi").unwrap();
83 let content = "-r other-requirements.txt\nrequests==2.31.0\n".to_string();
84
85 let parse_result = ecosystem
86 .parse_manifest(&content, &uri)
87 .await
88 .expect("Failed to parse manifest");
89
90 let doc_state =
91 DocumentState::new_from_parse_result(EcosystemId::Pypi, content, parse_result);
92 state.update_document(uri.clone(), doc_state);
93
94 let params = DocumentLinkParams {
95 text_document: TextDocumentIdentifier { uri },
96 work_done_progress_params: Default::default(),
97 partial_result_params: Default::default(),
98 };
99
100 let (client, config) = create_test_client_and_config();
101 let links = handle_document_link(state, params, client, config).await;
102
103 assert_eq!(links.len(), 1);
104 let target = links[0].target.as_ref().expect("link must have a target");
105 assert!(
106 target
107 .path()
108 .as_str()
109 .ends_with("/test/other-requirements.txt")
110 );
111 }
112 }
113}