From 88f4c2cdb0c540977a0e75fc29e63c839501552d Mon Sep 17 00:00:00 2001 From: He1pa <56333845+He1pa@users.noreply.github.com> Date: Wed, 21 Feb 2024 18:22:36 +0800 Subject: [PATCH] feat: enhance builtin func complete (#1064) * feat: enchance builtin function completion. 1. only complete builtin function in root scope. 2. Modify the label of the function's completion item to avoid fuzzy matching of function parameters to commonly used characters, such as x,y,z, and migrate function parameter descriptions to completion item detail Signed-off-by: he1pa <18012015693@163.com> * feat: complete builtin function in lambda scope Signed-off-by: he1pa <18012015693@163.com> --------- Signed-off-by: he1pa <18012015693@163.com> --- kclvm/sema/src/resolver/tests.rs | 2 +- kclvm/sema/src/ty/mod.rs | 7 -- kclvm/tools/src/LSP/src/completion.rs | 119 +++++++++++++++++++------- 3 files changed, 88 insertions(+), 40 deletions(-) diff --git a/kclvm/sema/src/resolver/tests.rs b/kclvm/sema/src/resolver/tests.rs index 35aafb0a5..26f426b2e 100644 --- a/kclvm/sema/src/resolver/tests.rs +++ b/kclvm/sema/src/resolver/tests.rs @@ -645,7 +645,7 @@ fn test_resolve_function_with_default_values() { let main_scope = scope.main_scope().unwrap(); let func = main_scope.borrow().lookup("is_alpha").unwrap(); assert!(func.borrow().ty.is_func()); - let func_ty = func.borrow().ty.into_function_ty(); + let func_ty = func.borrow().ty.into_func_type(); assert_eq!(func_ty.params.len(), 3); assert_eq!(func_ty.params[0].has_default, false); assert_eq!(func_ty.params[1].has_default, true); diff --git a/kclvm/sema/src/ty/mod.rs b/kclvm/sema/src/ty/mod.rs index 66a38022e..64b109f0a 100644 --- a/kclvm/sema/src/ty/mod.rs +++ b/kclvm/sema/src/ty/mod.rs @@ -96,13 +96,6 @@ impl Type { _ => None, } } - - pub fn into_function_ty(&self) -> FunctionType { - match &self.kind { - TypeKind::Function(func) => func.clone(), - _ => panic!("Not a function type"), - } - } } unsafe impl Send for TypeKind {} diff --git a/kclvm/tools/src/LSP/src/completion.rs b/kclvm/tools/src/LSP/src/completion.rs index 56ecb5d3c..72eb47851 100644 --- a/kclvm/tools/src/LSP/src/completion.rs +++ b/kclvm/tools/src/LSP/src/completion.rs @@ -28,7 +28,7 @@ use kclvm_config::modfile::KCL_FILE_EXTENSION; use kclvm_sema::core::global_state::GlobalState; use kclvm_error::Position as KCLPos; -use kclvm_sema::builtin::{STANDARD_SYSTEM_MODULES, STRING_MEMBER_FUNCTIONS}; +use kclvm_sema::builtin::{BUILTIN_FUNCTIONS, STANDARD_SYSTEM_MODULES, STRING_MEMBER_FUNCTIONS}; use kclvm_sema::core::package::ModuleInfo; use kclvm_sema::resolver::doc::{parse_doc_string, Doc}; use kclvm_sema::ty::{FunctionType, SchemaType, Type}; @@ -107,8 +107,52 @@ pub(crate) fn completion( })); } - // Complete all usable symbol obj in inner most scope if let Some(scope) = gs.look_up_scope(pos) { + // Complete builtin functions in root scope and lambda + match scope.get_kind() { + kclvm_sema::core::scope::ScopeKind::Local => { + if let Some(locol_scope) = gs.get_scopes().try_get_local_scope(&scope) { + match locol_scope.get_kind() { + kclvm_sema::core::scope::LocalSymbolScopeKind::Lambda => { + completions.extend(BUILTIN_FUNCTIONS.iter().map( + |(name, ty)| KCLCompletionItem { + label: func_ty_complete_label( + name, + &ty.into_func_type(), + ), + detail: Some( + ty.into_func_type().func_signature_str(name), + ), + documentation: ty.ty_doc(), + kind: Some(KCLCompletionItemKind::Function), + insert_text: Some(func_ty_complete_insert_text( + name, + &ty.into_func_type(), + )), + }, + )); + } + _ => {} + } + } + } + kclvm_sema::core::scope::ScopeKind::Root => { + completions.extend(BUILTIN_FUNCTIONS.iter().map(|(name, ty)| { + KCLCompletionItem { + label: func_ty_complete_label(name, &ty.into_func_type()), + detail: Some(ty.into_func_type().func_signature_str(name)), + documentation: ty.ty_doc(), + kind: Some(KCLCompletionItemKind::Function), + insert_text: Some(func_ty_complete_insert_text( + name, + &ty.into_func_type(), + )), + } + })); + } + } + + // Complete all usable symbol obj in inner most scope if let Some(defs) = gs.get_all_defs_in_scope(scope) { for symbol_ref in defs { match gs.get_symbols().get_symbol(symbol_ref) { @@ -138,9 +182,15 @@ pub(crate) fn completion( }); } _ => { + let detail = match &ty.kind { + kclvm_sema::ty::TypeKind::Function(func_ty) => { + func_ty.func_signature_str(&name) + } + _ => ty.ty_str(), + }; completions.insert(KCLCompletionItem { label: name, - detail: Some(ty.ty_str()), + detail: Some(detail), documentation: sema_info.doc.clone(), kind: type_to_item_kind(ty), insert_text: None, @@ -190,14 +240,16 @@ fn completion_dot( .map(|(name, ty)| KCLCompletionItem { label: func_ty_complete_label( name, - &ty.into_function_ty(), + &ty.into_func_type(), + ), + detail: Some( + ty.into_func_type().func_signature_str(name), ), - detail: Some(ty.ty_str()), documentation: ty.ty_doc(), kind: Some(KCLCompletionItemKind::Function), insert_text: Some(func_ty_complete_insert_text( name, - &ty.into_function_ty(), + &ty.into_func_type(), )), }) .collect(), @@ -639,17 +691,8 @@ fn pkg_real_name(pkg: &String, module: &ModuleInfo) -> String { pkg.split('.').last().unwrap().to_string() } -fn func_ty_complete_label(func_name: &String, func_type: &FunctionType) -> String { - format!( - "{}({})", - func_name, - func_type - .params - .iter() - .map(|param| param.name.clone()) - .collect::>() - .join(", "), - ) +fn func_ty_complete_label(func_name: &String, _func_type: &FunctionType) -> String { + format!("{}(…)", func_name,) } fn func_ty_complete_insert_text(func_name: &String, func_type: &FunctionType) -> String { @@ -715,7 +758,7 @@ pub(crate) fn into_completion_items(items: &IndexSet) -> Vec< mod tests { use indexmap::IndexSet; use kclvm_error::Position as KCLPos; - use kclvm_sema::builtin::{MATH_FUNCTION_TYPES, STRING_MEMBER_FUNCTIONS}; + use kclvm_sema::builtin::{BUILTIN_FUNCTIONS, MATH_FUNCTION_TYPES, STRING_MEMBER_FUNCTIONS}; use lsp_types::{CompletionItem, CompletionItemKind, CompletionResponse, InsertTextFormat}; use proc_macro_crate::bench_test; @@ -746,11 +789,20 @@ mod tests { CompletionResponse::List(_) => panic!("test failed"), }; - let mut expected_labels: Vec<&str> = vec![ + let mut expected_labels: Vec = vec![ "", // generate from error recovery of "pkg." "subpkg", "math", "Person", "Person{}", "P", "P{}", "p", "p1", "p2", "p3", "p4", "aaaa", - ]; + ] + .iter() + .map(|s| s.to_string()) + .collect(); + + expected_labels.extend( + BUILTIN_FUNCTIONS + .iter() + .map(|(name, func)| func_ty_complete_label(name, &func.into_func_type())), + ); got_labels.sort(); expected_labels.sort(); @@ -769,7 +821,10 @@ mod tests { CompletionResponse::List(_) => panic!("test failed"), }; - expected_labels = vec!["", "age", "math", "name", "subpkg"]; + expected_labels = vec!["", "age", "math", "name", "subpkg"] + .iter() + .map(|s| s.to_string()) + .collect(); got_labels.sort(); expected_labels.sort(); assert_eq!(got_labels, expected_labels); @@ -811,7 +866,7 @@ mod tests { }; let expected_labels: Vec = STRING_MEMBER_FUNCTIONS .iter() - .map(|(name, ty)| func_ty_complete_label(name, &ty.into_function_ty())) + .map(|(name, ty)| func_ty_complete_label(name, &ty.into_func_type())) .collect(); assert_eq!(got_labels, expected_labels); @@ -824,7 +879,7 @@ mod tests { }; let expected_insert_text: Vec = STRING_MEMBER_FUNCTIONS .iter() - .map(|(name, ty)| func_ty_complete_insert_text(name, &ty.into_function_ty())) + .map(|(name, ty)| func_ty_complete_insert_text(name, &ty.into_func_type())) .collect(); assert_eq!(got_insert_text, expected_insert_text); @@ -872,7 +927,7 @@ mod tests { }; let expected_labels: Vec = MATH_FUNCTION_TYPES .iter() - .map(|(name, ty)| func_ty_complete_label(name, &ty.into_function_ty())) + .map(|(name, ty)| func_ty_complete_label(name, &ty.into_func_type())) .collect(); assert_eq!(got_labels, expected_labels); @@ -891,7 +946,7 @@ mod tests { let expected_labels: Vec = STRING_MEMBER_FUNCTIONS .iter() - .map(|(name, ty)| func_ty_complete_label(name, &ty.into_function_ty())) + .map(|(name, ty)| func_ty_complete_label(name, &ty.into_func_type())) .collect(); assert_eq!(got_labels, expected_labels); @@ -947,7 +1002,7 @@ mod tests { }; let expected_labels: Vec = STRING_MEMBER_FUNCTIONS .iter() - .map(|(name, ty)| func_ty_complete_label(name, &ty.into_function_ty())) + .map(|(name, ty)| func_ty_complete_label(name, &ty.into_func_type())) .collect(); assert_eq!(got_labels, expected_labels); @@ -995,7 +1050,7 @@ mod tests { }; let expected_labels: Vec = MATH_FUNCTION_TYPES .iter() - .map(|(name, ty)| func_ty_complete_label(name, &ty.into_function_ty())) + .map(|(name, ty)| func_ty_complete_label(name, &ty.into_func_type())) .collect(); assert_eq!(got_labels, expected_labels); @@ -1008,7 +1063,7 @@ mod tests { }; let expected_insert_text: Vec = MATH_FUNCTION_TYPES .iter() - .map(|(name, ty)| func_ty_complete_insert_text(name, &ty.into_function_ty())) + .map(|(name, ty)| func_ty_complete_insert_text(name, &ty.into_func_type())) .collect(); assert_eq!(got_insert_text, expected_insert_text); @@ -1027,7 +1082,7 @@ mod tests { let expected_labels: Vec = STRING_MEMBER_FUNCTIONS .iter() - .map(|(name, ty)| func_ty_complete_label(name, &ty.into_function_ty())) + .map(|(name, ty)| func_ty_complete_label(name, &ty.into_func_type())) .collect(); assert_eq!(got_labels, expected_labels); @@ -1040,7 +1095,7 @@ mod tests { }; let expected_insert_text: Vec = STRING_MEMBER_FUNCTIONS .iter() - .map(|(name, ty)| func_ty_complete_insert_text(name, &ty.into_function_ty())) + .map(|(name, ty)| func_ty_complete_insert_text(name, &ty.into_func_type())) .collect(); assert_eq!(got_insert_text, expected_insert_text); @@ -1346,7 +1401,7 @@ mod tests { let expected_labels: Vec = STRING_MEMBER_FUNCTIONS .iter() - .map(|(name, ty)| func_ty_complete_label(name, &ty.into_function_ty())) + .map(|(name, ty)| func_ty_complete_label(name, &ty.into_func_type())) .collect(); assert_eq!(got_labels, expected_labels); @@ -1359,7 +1414,7 @@ mod tests { }; let expected_insert_text: Vec = STRING_MEMBER_FUNCTIONS .iter() - .map(|(name, ty)| func_ty_complete_insert_text(name, &ty.into_function_ty())) + .map(|(name, ty)| func_ty_complete_insert_text(name, &ty.into_func_type())) .collect(); assert_eq!(got_insert_text, expected_insert_text);