php_lsp/editing/
use_import.rs1#![cfg_attr(target_family = "wasm", allow(dead_code))]
3
4use std::collections::HashMap;
5use std::sync::Arc;
6
7use tower_lsp_server::ls_types::{Position, Range, TextEdit, Uri, WorkspaceEdit};
8
9use crate::document::ast::ParsedDoc;
10use crate::lang::file_header::use_insert_line;
11use crate::types::resolve::{Declaration, resolve_declaration};
12
13pub(crate) fn find_fqn_for_function(
14 name: &str,
15 get_doc: &dyn Fn(&Uri) -> Option<Arc<ParsedDoc>>,
16 function_candidates: &dyn Fn(&str) -> Vec<Uri>,
17) -> Option<String> {
18 for uri in function_candidates(name) {
19 let Some(doc) = get_doc(&uri) else { continue };
20 let Some(decl) = resolve_declaration(&doc.program().stmts, name, &|decl| {
21 matches!(decl, Declaration::Function { .. })
22 }) else {
23 continue;
24 };
25 if let Declaration::Function { decl, .. } = decl {
26 let ns = doc
27 .program()
28 .stmts
29 .iter()
30 .find_map(|stmt| {
31 if let php_ast::StmtKind::Namespace(ns) = &stmt.kind {
32 ns.name.as_ref().map(|n| n.to_string_repr().to_string())
33 } else {
34 None
35 }
36 })
37 .unwrap_or_default();
38 if ns.is_empty() {
39 continue;
40 }
41 return Some(format!(
42 "{}\\{}",
43 ns.trim_start_matches('\\'),
44 decl.name.or_error()
45 ));
46 }
47 }
48 None
49}
50
51pub(crate) fn build_use_import_edit(
53 doc: &ParsedDoc,
54 at: Position,
55 uri: &Uri,
56 fqn: &str,
57) -> WorkspaceEdit {
58 let insert_line = find_use_insert_line(doc, at);
59 let insert_text = format!("use {fqn};\n");
60 let pos = Position {
61 line: insert_line,
62 character: 0,
63 };
64 let edit = TextEdit {
65 range: Range {
66 start: pos,
67 end: pos,
68 },
69 new_text: insert_text,
70 };
71 let mut changes = HashMap::new();
72 changes.insert(uri.clone(), vec![edit]);
73 WorkspaceEdit {
74 changes: Some(changes),
75 ..Default::default()
76 }
77}
78
79pub(crate) fn build_use_function_import_edit(
81 doc: &ParsedDoc,
82 at: Position,
83 uri: &Uri,
84 fqn: &str,
85) -> WorkspaceEdit {
86 let insert_line = find_use_insert_line(doc, at);
87 let insert_text = format!("use function {fqn};\n");
88 let pos = Position {
89 line: insert_line,
90 character: 0,
91 };
92 let edit = TextEdit {
93 range: Range {
94 start: pos,
95 end: pos,
96 },
97 new_text: insert_text,
98 };
99 let mut changes = HashMap::new();
100 changes.insert(uri.clone(), vec![edit]);
101 WorkspaceEdit {
102 changes: Some(changes),
103 ..Default::default()
104 }
105}
106
107pub(crate) fn find_use_insert_line(doc: &ParsedDoc, at: Position) -> u32 {
108 use_insert_line(doc, at, |_| true)
109}