Skip to content

Commit ca28e90

Browse files
committed
completion: optimize table_field
1 parent 45971ad commit ca28e90

File tree

7 files changed

+156
-77
lines changed

7 files changed

+156
-77
lines changed

crates/emmylua_ls/src/handlers/completion/add_completions/add_member_completion.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use emmylua_code_analysis::{DbIndex, LuaMemberInfo, LuaMemberKey, LuaType};
1+
use emmylua_code_analysis::{DbIndex, LuaMemberInfo, LuaMemberKey, LuaPropertyOwnerId, LuaType};
22
use emmylua_parser::LuaTokenKind;
33
use lsp_types::CompletionItem;
44

@@ -105,6 +105,19 @@ pub fn add_member_completion(
105105
builder.add_completion_item(completion_item)?;
106106

107107
// add overloads if the type is function
108+
add_signature_overloads(builder, property_owner, &typ, display, deprecated, label)?;
109+
110+
Some(())
111+
}
112+
113+
fn add_signature_overloads(
114+
builder: &mut CompletionBuilder,
115+
property_owner: &Option<LuaPropertyOwnerId>,
116+
typ: &LuaType,
117+
display: CallDisplay,
118+
deprecated: Option<bool>,
119+
label: String,
120+
) -> Option<()> {
108121
if let LuaType::Signature(signature_id) = typ {
109122
let overloads = builder
110123
.semantic_model
@@ -141,7 +154,6 @@ pub fn add_member_completion(
141154
builder.add_completion_item(completion_item);
142155
});
143156
};
144-
145157
Some(())
146158
}
147159

crates/emmylua_ls/src/handlers/completion/add_completions/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use emmylua_code_analysis::humanize_type;
1414

1515
use super::completion_builder::CompletionBuilder;
1616

17-
fn check_visibility(builder: &mut CompletionBuilder, id: LuaPropertyOwnerId) -> Option<()> {
17+
pub fn check_visibility(builder: &mut CompletionBuilder, id: LuaPropertyOwnerId) -> Option<()> {
1818
match id {
1919
LuaPropertyOwnerId::Member(_) => {}
2020
LuaPropertyOwnerId::LuaDecl(_) => {}
@@ -45,7 +45,7 @@ fn get_completion_kind(typ: &LuaType) -> CompletionItemKind {
4545
CompletionItemKind::VARIABLE
4646
}
4747

48-
fn is_deprecated(builder: &CompletionBuilder, id: LuaPropertyOwnerId) -> bool {
48+
pub fn is_deprecated(builder: &CompletionBuilder, id: LuaPropertyOwnerId) -> bool {
4949
let property = builder
5050
.semantic_model
5151
.get_db()

crates/emmylua_ls/src/handlers/completion/completion_builder.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ pub struct CompletionBuilder<'a> {
1414
stopped: bool,
1515
// 主动触发补全
1616
pub is_invoke_completion: bool,
17+
pub env_start_index: i32,
18+
pub env_end_index: i32,
1719
}
1820

1921
impl<'a> CompletionBuilder<'a> {
@@ -31,6 +33,8 @@ impl<'a> CompletionBuilder<'a> {
3133
cancel_token,
3234
stopped: false,
3335
is_invoke_completion,
36+
env_start_index: -1,
37+
env_end_index: -1,
3438
}
3539
}
3640

@@ -58,4 +62,18 @@ impl<'a> CompletionBuilder<'a> {
5862
pub fn get_trigger_text(&self) -> String {
5963
self.trigger_token.text().trim_end().to_string()
6064
}
65+
66+
pub fn remove_env_completion_items(&mut self) {
67+
if self.env_start_index == -1 || self.env_end_index == -1 {
68+
return;
69+
}
70+
if self.env_start_index <= self.env_end_index
71+
&& self.env_end_index < self.completion_items.len() as i32
72+
{
73+
self.completion_items
74+
.drain(self.env_start_index as usize..=self.env_end_index as usize);
75+
}
76+
self.env_start_index = -1;
77+
self.env_end_index = -1;
78+
}
6179
}

crates/emmylua_ls/src/handlers/completion/providers/env_provider.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,16 @@ pub fn add_completion(builder: &mut CompletionBuilder) -> Option<()> {
1717
LuaAst::LuaNameExpr(_) => {}
1818
LuaAst::LuaBlock(_) => {}
1919
LuaAst::LuaCallArgList(_) => {}
20-
// 在表中无键时主动触发的补全, 不在这里处理
21-
// TODO 如果左值类型不是类而是纯表则允许
22-
LuaAst::LuaTableExpr(_)|
2320
// 字符串中触发的补全
24-
LuaAst::LuaLiteralExpr(_) => return None,
25-
_ => {},
21+
LuaAst::LuaLiteralExpr(_) => return None,
22+
_ => {}
2623
};
2724

2825
let mut duplicated_name = HashSet::new();
26+
builder.env_start_index = builder.get_completion_items_mut().len() as i32;
2927
add_local_env(builder, &mut duplicated_name, &node);
3028
add_global_env(builder, &mut duplicated_name);
29+
builder.env_end_index = builder.get_completion_items_mut().len() as i32 - 1;
3130

3231
builder.env_duplicate_name.extend(duplicated_name);
3332

crates/emmylua_ls/src/handlers/completion/providers/mod.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ mod keywords_provider;
88
mod member_provider;
99
mod module_path_provider;
1010
mod postfix_provider;
11-
mod table_decl_field_provider;
11+
mod table_field_provider;
1212
mod type_special_provider;
1313

1414
use emmylua_parser::{LuaAst, LuaAstNode, LuaAstToken, LuaStringToken};
@@ -28,25 +28,29 @@ pub fn add_completions(builder: &mut CompletionBuilder) -> Option<()> {
2828
_ => return Some(()),
2929
}
3030
}
31+
postfix_provider::add_completion(builder);
32+
env_provider::add_completion(builder);
33+
// 只有具有类型定义的表才会成功返回, 此时我们不需要处理其他补全
34+
if table_field_provider::add_completion(builder).is_some() {
35+
return Some(());
36+
}
37+
type_special_provider::add_completion(builder);
38+
member_provider::add_completion(builder);
39+
keywords_provider::add_completion(builder);
3140

3241
module_path_provider::add_completion(builder);
3342
file_path_provider::add_completion(builder);
34-
keywords_provider::add_completion(builder);
35-
type_special_provider::add_completion(builder);
36-
env_provider::add_completion(builder);
37-
member_provider::add_completion(builder);
38-
table_decl_field_provider::add_completion(builder);
3943
auto_require_provider::add_completion(builder);
4044
doc_tag_provider::add_completion(builder);
4145
doc_type_provider::add_completion(builder);
4246
doc_name_token_provider::add_completion(builder);
43-
postfix_provider::add_completion(builder);
4447

4548
for (index, item) in builder.get_completion_items_mut().iter_mut().enumerate() {
4649
if item.sort_text.is_none() {
4750
item.sort_text = Some(format!("{:04}", index));
4851
}
4952
}
53+
// dbg!(&builder.get_completion_items_mut());
5054

5155
Some(())
5256
}

crates/emmylua_ls/src/handlers/completion/providers/table_decl_field_provider.rs

Lines changed: 0 additions & 61 deletions
This file was deleted.
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
use std::collections::HashSet;
2+
3+
use emmylua_code_analysis::{LuaMemberInfo, LuaMemberKey};
4+
use emmylua_parser::{LuaAst, LuaAstNode, LuaTableExpr, LuaTableField};
5+
use lsp_types::CompletionItem;
6+
7+
use crate::handlers::completion::{
8+
add_completions::{check_visibility, is_deprecated, CompletionData},
9+
completion_builder::CompletionBuilder,
10+
};
11+
12+
pub fn add_completion(builder: &mut CompletionBuilder) -> Option<()> {
13+
let table_expr = get_table_expr(builder)?;
14+
let table_type = builder
15+
.semantic_model
16+
.infer_table_should_be(table_expr.clone())?;
17+
let member_infos = builder.semantic_model.infer_member_infos(&table_type)?;
18+
19+
let mut duplicated_set = HashSet::new();
20+
for field in table_expr.get_fields() {
21+
let key = field.get_field_key();
22+
if let Some(key) = key {
23+
duplicated_set.insert(key.get_path_part());
24+
}
25+
}
26+
27+
for member_info in member_infos {
28+
if duplicated_set.contains(&member_info.key.to_path()) {
29+
continue;
30+
}
31+
32+
duplicated_set.insert(member_info.key.to_path());
33+
add_table_field_completion(builder, member_info);
34+
}
35+
36+
// 删除env补全项
37+
builder.remove_env_completion_items();
38+
Some(())
39+
}
40+
41+
fn get_table_expr(builder: &mut CompletionBuilder) -> Option<LuaTableExpr> {
42+
let node = LuaAst::cast(builder.trigger_token.parent()?)?;
43+
44+
match node {
45+
LuaAst::LuaTableExpr(table_expr) => Some(table_expr),
46+
LuaAst::LuaNameExpr(name_expr) => name_expr
47+
.get_parent::<LuaTableField>()?
48+
.get_parent::<LuaTableExpr>(),
49+
_ => None,
50+
}
51+
}
52+
53+
fn add_table_field_completion(
54+
builder: &mut CompletionBuilder,
55+
member_info: LuaMemberInfo,
56+
) -> Option<()> {
57+
let env_completion = &builder.env_duplicate_name;
58+
let name = match member_info.key {
59+
LuaMemberKey::Name(name) => name.to_string(),
60+
LuaMemberKey::Integer(index) => format!("[{}]", index),
61+
_ => return None,
62+
};
63+
let typ = member_info.typ;
64+
65+
let (label, insert_text) = {
66+
let is_nullable = if typ.is_nullable() { "?" } else { "" };
67+
if env_completion.contains(&name) {
68+
(
69+
format!("{0}{1} = {0},", name, is_nullable),
70+
format!("{0} = {0},", name),
71+
)
72+
} else {
73+
(
74+
format!("{0}{1} = ", name, is_nullable),
75+
format!("{0} = ", name),
76+
)
77+
}
78+
};
79+
80+
let property_owner = &member_info.property_owner_id;
81+
if let Some(property_owner) = &property_owner {
82+
check_visibility(builder, property_owner.clone())?;
83+
}
84+
85+
let data = if let Some(id) = &property_owner {
86+
CompletionData::from_property_owner_id(id.clone().into())
87+
} else {
88+
None
89+
};
90+
let deprecated = if let Some(id) = &property_owner {
91+
Some(is_deprecated(builder, id.clone()))
92+
} else {
93+
None
94+
};
95+
96+
let completion_item = CompletionItem {
97+
label,
98+
kind: Some(lsp_types::CompletionItemKind::PROPERTY),
99+
data,
100+
deprecated,
101+
insert_text: Some(insert_text),
102+
..Default::default()
103+
};
104+
105+
builder.add_completion_item(completion_item);
106+
Some(())
107+
}

0 commit comments

Comments
 (0)