php_lsp/editing/
use_import.rs1use std::collections::HashMap;
2
3use tower_lsp::lsp_types::{Position, Range, TextEdit, Url, WorkspaceEdit};
4
5use crate::index::file_index::FileIndex;
6
7pub(crate) fn find_fqn_for_class(
14 name: &str,
15 indexes: &[(Url, std::sync::Arc<FileIndex>)],
16) -> Option<String> {
17 for (_uri, idx) in indexes {
18 for class in &idx.classes {
19 if class.name.as_ref() == name {
20 return Some(class.fqn.to_string());
21 }
22 }
23 }
24 None
25}
26
27pub(crate) fn build_use_import_edit(source: &str, uri: &Url, fqn: &str) -> WorkspaceEdit {
29 let insert_line = find_use_insert_line(source);
31 let insert_text = format!("use {fqn};\n");
32 let pos = Position {
33 line: insert_line,
34 character: 0,
35 };
36 let edit = TextEdit {
37 range: Range {
38 start: pos,
39 end: pos,
40 },
41 new_text: insert_text,
42 };
43 let mut changes = HashMap::new();
44 changes.insert(uri.clone(), vec![edit]);
45 WorkspaceEdit {
46 changes: Some(changes),
47 ..Default::default()
48 }
49}
50
51pub(crate) fn find_fqn_for_function(
54 name: &str,
55 indexes: &[(Url, std::sync::Arc<FileIndex>)],
56) -> Option<String> {
57 for (_uri, idx) in indexes {
58 for func in &idx.functions {
59 if func.name.as_ref() == name && func.fqn.contains('\\') {
60 return Some(func.fqn.trim_start_matches('\\').to_string());
61 }
62 }
63 }
64 None
65}
66
67pub(crate) fn build_use_function_import_edit(source: &str, uri: &Url, fqn: &str) -> WorkspaceEdit {
69 let insert_line = find_use_insert_line(source);
70 let insert_text = format!("use function {fqn};\n");
71 let pos = Position {
72 line: insert_line,
73 character: 0,
74 };
75 let edit = TextEdit {
76 range: Range {
77 start: pos,
78 end: pos,
79 },
80 new_text: insert_text,
81 };
82 let mut changes = HashMap::new();
83 changes.insert(uri.clone(), vec![edit]);
84 WorkspaceEdit {
85 changes: Some(changes),
86 ..Default::default()
87 }
88}
89
90pub(crate) fn find_use_insert_line(source: &str) -> u32 {
91 let mut last_use_or_ns: u32 = 0;
92 for (i, line) in source.lines().enumerate() {
93 let trimmed = line.trim();
94 if trimmed.starts_with("<?php")
95 || trimmed.starts_with("namespace ")
96 || trimmed.starts_with("use ")
97 {
98 last_use_or_ns = i as u32 + 1;
99 }
100 }
101 last_use_or_ns
102}