Handle a `textDocument/documentLink` request. Parses the file and walks the AST for include/require expressions.
(&self, uri: &str, content: &str)
| 29 | /// |
| 30 | /// Parses the file and walks the AST for include/require expressions. |
| 31 | pub fn handle_document_link(&self, uri: &str, content: &str) -> Option<Vec<DocumentLink>> { |
| 32 | let file_path = Url::parse(uri).ok().and_then(|u| u.to_file_path().ok()); |
| 33 | let file_dir = file_path.as_deref().and_then(|p| p.parent()); |
| 34 | |
| 35 | let arena = Bump::new(); |
| 36 | let file_id = mago_database::file::FileId::new("input.php"); |
| 37 | let program = mago_syntax::parser::parse_file_content(&arena, file_id, content); |
| 38 | |
| 39 | let mut links: Vec<DocumentLink> = Vec::new(); |
| 40 | |
| 41 | if let Some(dir) = file_dir { |
| 42 | let mut include_links = Vec::new(); |
| 43 | for stmt in program.statements.iter() { |
| 44 | collect_include_links_from_statement(stmt, content, dir, &mut include_links); |
| 45 | } |
| 46 | for il in include_links { |
| 47 | if let Ok(target_url) = Url::from_file_path(&il.resolved_path) { |
| 48 | let start = offset_to_position(content, il.start_offset); |
| 49 | let end = offset_to_position(content, il.end_offset); |
| 50 | links.push(DocumentLink { |
| 51 | range: Range { start, end }, |
| 52 | target: Some(target_url), |
| 53 | tooltip: Some(il.resolved_path.display().to_string()), |
| 54 | data: None, |
| 55 | }); |
| 56 | } |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | if links.is_empty() { None } else { Some(links) } |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | // ─── AST walking for include/require ──────────────────────────────────────── |
no test coverage detected