Skip to content

Commit 2e87282

Browse files
committed
[New] 重命名支持索引访问
1 parent 6ccc25e commit 2e87282

5 files changed

Lines changed: 123 additions & 43 deletions

File tree

crates/emmylua_ls/src/handlers/rename/mod.rs

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ mod rename_type;
55
use std::collections::HashMap;
66

77
use emmylua_code_analysis::{LuaCompilation, LuaSemanticDeclId, SemanticDeclLevel, SemanticModel};
8-
use emmylua_parser::{LuaAstNode, LuaSyntaxToken, LuaTokenKind};
8+
use emmylua_parser::{LuaAstNode, LuaLiteralExpr, LuaSyntaxToken, LuaTableField, LuaTokenKind};
99
use lsp_types::{
1010
ClientCapabilities, OneOf, PrepareRenameResponse, RenameOptions, RenameParams,
1111
ServerCapabilities, TextDocumentPositionParams, WorkspaceEdit,
@@ -29,37 +29,7 @@ pub async fn on_rename_handler(
2929
let analysis = context.analysis.read().await;
3030
let file_id = analysis.get_file_id(&uri)?;
3131
let position = params.text_document_position.position;
32-
let mut semantic_model = analysis.compilation.get_semantic_model(file_id)?;
33-
let root = semantic_model.get_root();
34-
let position_offset = {
35-
let document = semantic_model.get_document();
36-
document.get_offset(position.line as usize, position.character as usize)?
37-
};
38-
39-
if position_offset > root.syntax().text_range().end() {
40-
return None;
41-
}
42-
43-
let token = match root.syntax().token_at_offset(position_offset) {
44-
TokenAtOffset::Single(token) => token,
45-
TokenAtOffset::Between(left, right) => {
46-
if left.kind() == LuaTokenKind::TkName.into() {
47-
left
48-
} else {
49-
right
50-
}
51-
}
52-
TokenAtOffset::None => {
53-
return None;
54-
}
55-
};
56-
57-
rename_references(
58-
&mut semantic_model,
59-
&analysis.compilation,
60-
token,
61-
params.new_name,
62-
)
32+
rename(&analysis, file_id, position, params.new_name)
6333
}
6434

6535
pub async fn on_prepare_rename_handler(
@@ -94,7 +64,6 @@ pub async fn on_prepare_rename_handler(
9464
return None;
9565
}
9666
};
97-
9867
if matches!(
9968
token.kind().into(),
10069
LuaTokenKind::TkName | LuaTokenKind::TkInt | LuaTokenKind::TkString
@@ -107,14 +76,55 @@ pub async fn on_prepare_rename_handler(
10776
}
10877
}
10978

79+
pub fn rename(
80+
analysis: &emmylua_code_analysis::EmmyLuaAnalysis,
81+
file_id: emmylua_code_analysis::FileId,
82+
position: lsp_types::Position,
83+
new_name: String,
84+
) -> Option<WorkspaceEdit> {
85+
let mut semantic_model = analysis.compilation.get_semantic_model(file_id)?;
86+
let root = semantic_model.get_root();
87+
let position_offset = {
88+
let document = semantic_model.get_document();
89+
document.get_offset(position.line as usize, position.character as usize)?
90+
};
91+
92+
if position_offset > root.syntax().text_range().end() {
93+
return None;
94+
}
95+
96+
let token = match root.syntax().token_at_offset(position_offset) {
97+
TokenAtOffset::Single(token) => token,
98+
TokenAtOffset::Between(left, right) => {
99+
if left.kind() == LuaTokenKind::TkName.into() {
100+
left
101+
} else {
102+
right
103+
}
104+
}
105+
TokenAtOffset::None => {
106+
return None;
107+
}
108+
};
109+
110+
rename_references(&mut semantic_model, &analysis.compilation, token, new_name)
111+
}
112+
110113
fn rename_references(
111114
semantic_model: &SemanticModel,
112115
compilation: &LuaCompilation,
113116
token: LuaSyntaxToken,
114117
new_name: String,
115118
) -> Option<WorkspaceEdit> {
116119
let mut result = HashMap::new();
117-
let semantic_decl = semantic_model.find_decl(token.into(), SemanticDeclLevel::NoTrace)?;
120+
let semantic_decl = match try_get_table_field(token.clone()) {
121+
Some(table_field) => semantic_model.find_decl(
122+
table_field.syntax().clone().into(),
123+
SemanticDeclLevel::NoTrace,
124+
),
125+
None => semantic_model.find_decl(token.into(), SemanticDeclLevel::NoTrace),
126+
}?;
127+
118128
match semantic_decl {
119129
LuaSemanticDeclId::LuaDecl(decl_id) => {
120130
rename_decl_references(semantic_model, compilation, decl_id, new_name, &mut result);
@@ -159,6 +169,12 @@ fn rename_references(
159169
})
160170
}
161171

172+
fn try_get_table_field(token: LuaSyntaxToken) -> Option<LuaTableField> {
173+
let parent = token.parent()?;
174+
let literal_expr = LuaLiteralExpr::cast(parent)?;
175+
literal_expr.get_parent::<LuaTableField>()
176+
}
177+
162178
pub struct RenameCapabilities;
163179

164180
impl RegisterCapabilities for RenameCapabilities {

crates/emmylua_ls/src/handlers/rename/rename_member.rs

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use std::collections::HashMap;
33
use emmylua_code_analysis::{
44
LuaCompilation, LuaMemberId, LuaSemanticDeclId, SemanticDeclLevel, SemanticModel,
55
};
6-
use emmylua_parser::{LuaAst, LuaAstNode, LuaAstToken, LuaNameToken, LuaSyntaxNode};
6+
use emmylua_parser::{
7+
LuaAst, LuaAstNode, LuaAstToken, LuaIndexToken, LuaLiteralExpr, LuaNameToken, LuaSyntaxNode,
8+
LuaTokenKind,
9+
};
710
use lsp_types::Uri;
811

912
use crate::handlers::hover::find_member_origin_owner;
@@ -44,11 +47,13 @@ pub fn rename_member_references(
4447
property_owner.clone(),
4548
SemanticDeclLevel::NoTrace,
4649
) {
47-
let range = get_member_name_token_lsp_range(semantic_model, node.clone())?;
48-
result
49-
.entry(semantic_model.get_document().get_uri())
50-
.or_insert_with(HashMap::new)
51-
.insert(range, new_name.clone());
50+
let range = get_member_name_token_lsp_range(semantic_model, node.clone());
51+
if let Some(range) = range {
52+
result
53+
.entry(semantic_model.get_document().get_uri())
54+
.or_insert_with(HashMap::new)
55+
.insert(range, new_name.clone());
56+
}
5257
}
5358
}
5459

@@ -61,7 +66,20 @@ fn get_member_name_token_lsp_range(
6166
) -> Option<lsp_types::Range> {
6267
let document = semantic_model.get_document();
6368
let node = LuaAst::cast(node)?;
64-
// todo
65-
let token = node.token::<LuaNameToken>()?;
66-
document.to_lsp_range(token.get_range())
69+
if let Some(token) = node.token::<LuaNameToken>() {
70+
return document.to_lsp_range(token.get_range());
71+
}
72+
73+
// 此时可能是 [] 访问
74+
if let Some(_) = node.token::<LuaIndexToken>() {
75+
let literal = node.child::<LuaLiteralExpr>()?.get_literal()?;
76+
if matches!(
77+
literal.get_token_kind(),
78+
LuaTokenKind::TkInt | LuaTokenKind::TkString
79+
) {
80+
return document.to_lsp_range(literal.get_range());
81+
}
82+
}
83+
84+
None
6785
}

crates/emmylua_ls/src/handlers/test/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ mod hover_function_test;
66
mod hover_test;
77
mod implementation_test;
88
mod inlay_hint_test;
9+
mod rename_test;
910
mod semantic_token_test;
1011
mod signature_helper_test;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#[cfg(test)]
2+
mod tests {
3+
use crate::handlers::test_lib::ProviderVirtualWorkspace;
4+
5+
#[test]
6+
fn test_int_key() {
7+
let mut ws = ProviderVirtualWorkspace::new();
8+
let result = ws.check_rename(
9+
r#"
10+
local export = {
11+
[<??>1] = 1,
12+
}
13+
14+
export[1] = 2
15+
"#,
16+
"2".to_string(),
17+
2,
18+
);
19+
assert!(result);
20+
}
21+
}

crates/emmylua_ls/src/handlers/test_lib/mod.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,4 +350,28 @@ impl ProviderVirtualWorkspace {
350350
dbg!(&data);
351351
Some(result)
352352
}
353+
354+
pub fn check_rename(&mut self, block_str: &str, new_name: String, len: usize) -> bool {
355+
let content = Self::handle_file_content(block_str);
356+
let Some((content, position)) = content else {
357+
return false;
358+
};
359+
let file_id = self.def(&content);
360+
let result = rename(&self.analysis, file_id, position, new_name.clone());
361+
let Some(result) = result else {
362+
return false;
363+
};
364+
// dbg!(&result);
365+
if let Some(changes) = result.changes {
366+
let mut count = 0;
367+
for (_, edits) in changes {
368+
count += edits.len();
369+
}
370+
if count != len {
371+
return false;
372+
}
373+
}
374+
375+
true
376+
}
353377
}

0 commit comments

Comments
 (0)