1use std::path::Path;
2
3use anyhow::Context;
4use serde_json::{json, Value};
5
6use crate::commands::find::resolve_symbol_location;
7use crate::commands::workspace_edit::{apply_workspace_edit, count_workspace_edits};
8use crate::lsp::client::{path_to_uri, LspClient};
9use crate::lsp::files::FileTracker;
10
11pub async fn handle_rename(
20 name: &str,
21 new_name: &str,
22 client: &mut LspClient,
23 file_tracker: &mut FileTracker,
24 project_root: &Path,
25) -> anyhow::Result<Value> {
26 let (abs_path, line, character) = resolve_symbol_location(name, client, project_root).await?;
27
28 file_tracker
29 .ensure_open(&abs_path, client.transport_mut())
30 .await?;
31
32 let uri = path_to_uri(&abs_path)?;
33 let params = json!({
34 "textDocument": { "uri": uri.as_str() },
35 "position": { "line": line, "character": character },
36 "newName": new_name
37 });
38
39 let request_id = client
40 .transport_mut()
41 .send_request("textDocument/rename", params)
42 .await?;
43
44 let workspace_edit = client
45 .wait_for_response_public(request_id)
46 .await
47 .context("textDocument/rename request failed")?;
48
49 if workspace_edit.is_null() {
50 return Ok(json!({
51 "files_changed": 0,
52 "refs_changed": 0,
53 }));
54 }
55
56 let refs_changed = count_workspace_edits(&workspace_edit);
57 let modified = apply_workspace_edit(&workspace_edit, project_root)?;
58
59 Ok(json!({
60 "files_changed": modified.len(),
61 "refs_changed": refs_changed,
62 }))
63}
64
65#[cfg(test)]
66mod tests {
67 use serde_json::json;
68
69 #[test]
70 fn rename_response_shape() {
71 let data = json!({ "files_changed": 3, "refs_changed": 12 });
72 assert_eq!(data["files_changed"].as_u64(), Some(3));
73 assert_eq!(data["refs_changed"].as_u64(), Some(12));
74 }
75}