Skip to content

Commit

Permalink
fix: fix lsp completion for newline char (#926)
Browse files Browse the repository at this point in the history
* fix: fix lsp completion. 1.dot completion of schema attr with schema type 2. newline completion of schema attr when cursor in schemastmt

Signed-off-by: he1pa <[email protected]>

* chore: fmt code

Signed-off-by: he1pa <[email protected]>

* test: fix ut

Signed-off-by: he1pa <[email protected]>

---------

Signed-off-by: he1pa <[email protected]>
  • Loading branch information
He1pa authored Nov 28, 2023
1 parent 5ab79bb commit e226b9a
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 41 deletions.
116 changes: 77 additions & 39 deletions kclvm/tools/src/LSP/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use kclvm_sema::resolver::doc::{parse_doc_string, Doc};
use kclvm_sema::ty::{FunctionType, SchemaType, Type};
use lsp_types::{CompletionItem, CompletionItemKind};

use crate::util::get_real_path_from_external;
use crate::util::{get_real_path_from_external, is_in_schema_expr};
use crate::util::{inner_most_expr_in_stmt, is_in_docstring};

#[derive(Debug, Clone, PartialEq, Hash, Eq)]
Expand Down Expand Up @@ -217,9 +217,6 @@ fn completion_dot(
match &sema_info.ty {
Some(ty) => {
let label: String = match &ty.kind {
kclvm_sema::ty::TypeKind::Schema(schema) => {
schema_ty_completion_item(schema).label
}
kclvm_sema::ty::TypeKind::Function(func_ty) => {
func_ty_complete_label(&name, func_ty)
}
Expand Down Expand Up @@ -330,44 +327,46 @@ fn completion_newline(
return Some(into_completion_items(&completions).into());
}

// Complete schema attr when input newline in schema
if let Some(scope) = gs.look_up_scope(pos) {
if let Some(defs) = gs.get_all_defs_in_scope(scope) {
for symbol_ref in defs {
match gs.get_symbols().get_symbol(symbol_ref) {
Some(def) => {
let sema_info = def.get_sema_info();
let name = def.get_name();
match symbol_ref.get_kind() {
kclvm_sema::core::symbol::SymbolKind::Attribute => {
completions.insert(KCLCompletionItem {
label: name.clone(),
detail: sema_info
.ty
.as_ref()
.map(|ty| format!("{}: {}", name, ty.ty_str())),
documentation: match &sema_info.doc {
Some(doc) => {
if doc.is_empty() {
None
} else {
Some(doc.clone())
// todo: judge based on scope kind instead of `is_in_schema_expr`
if let Some(_) = is_in_schema_expr(program, pos) {
// Complete schema attr when input newline in schema
if let Some(scope) = gs.look_up_scope(pos) {
if let Some(defs) = gs.get_all_defs_in_scope(scope) {
for symbol_ref in defs {
match gs.get_symbols().get_symbol(symbol_ref) {
Some(def) => {
let sema_info = def.get_sema_info();
let name = def.get_name();
match symbol_ref.get_kind() {
kclvm_sema::core::symbol::SymbolKind::Attribute => {
completions.insert(KCLCompletionItem {
label: name.clone(),
detail: sema_info
.ty
.as_ref()
.map(|ty| format!("{}: {}", name, ty.ty_str())),
documentation: match &sema_info.doc {
Some(doc) => {
if doc.is_empty() {
None
} else {
Some(doc.clone())
}
}
}
None => None,
},
kind: Some(KCLCompletionItemKind::SchemaAttr),
});
None => None,
},
kind: Some(KCLCompletionItemKind::SchemaAttr),
});
}
_ => {}
}
_ => {}
}
None => {}
}
None => {}
}
}
}
}

Some(into_completion_items(&completions).into())
}

Expand Down Expand Up @@ -697,7 +696,7 @@ mod tests {
CompletionResponse::List(_) => panic!("test failed"),
};

let expected_labels: Vec<&str> = vec!["Person1{}"];
let expected_labels: Vec<&str> = vec!["Person1"];
assert_eq!(got_labels, expected_labels);

let pos = KCLPos {
Expand Down Expand Up @@ -820,7 +819,7 @@ mod tests {
CompletionResponse::List(_) => panic!("test failed"),
};

let expected_labels: Vec<&str> = vec!["Person1{}"];
let expected_labels: Vec<&str> = vec!["Person1"];
assert_eq!(got_labels, expected_labels);

let pos = KCLPos {
Expand Down Expand Up @@ -1025,7 +1024,6 @@ mod tests {
let (file, program, _, _, gs) =
compile_test_file("src/test_data/completion_test/schema/schema.k");

// test completion for builtin packages
let pos = KCLPos {
filename: file.to_owned(),
line: 7,
Expand Down Expand Up @@ -1058,7 +1056,6 @@ mod tests {
let (file, program, _, _, gs) =
compile_test_file("src/test_data/completion_test/newline/newline.k");

// test completion for builtin packages
let pos = KCLPos {
filename: file.to_owned(),
line: 8,
Expand All @@ -1082,14 +1079,27 @@ mod tests {
}
CompletionResponse::List(_) => panic!("test failed"),
}

// not complete in schema stmt
let pos = KCLPos {
filename: file.to_owned(),
line: 5,
column: Some(4),
};
let got = completion(Some('\n'), &program, &pos, &prog_scope, &gs).unwrap();
match got {
CompletionResponse::Array(arr) => {
assert!(arr.is_empty())
}
CompletionResponse::List(_) => panic!("test failed"),
}
}

#[test]
fn schema_docstring_newline_completion() {
let (file, program, _, _, gs) =
compile_test_file("src/test_data/completion_test/newline/docstring_newline.k");

// test completion for builtin packages
let pos = KCLPos {
filename: file.to_owned(),
line: 3,
Expand Down Expand Up @@ -1178,4 +1188,32 @@ mod tests {
CompletionResponse::List(_) => panic!("test failed"),
};
}

#[test]
fn schema_ty_attr_complete() {
let (file, program, prog_scope, _, gs) =
compile_test_file("src/test_data/completion_test/dot/schema_ty_attr/schema_ty_attr.k");

let pos = KCLPos {
filename: file.to_owned(),
line: 13,
column: Some(2),
};

let got = completion(Some('.'), &program, &pos, &prog_scope, &gs).unwrap();
match got {
CompletionResponse::Array(arr) => {
assert_eq!(
arr[0],
CompletionItem {
label: "name".to_string(),
detail: Some("name: Name".to_string()),
kind: Some(CompletionItemKind::FIELD),
..Default::default()
}
)
}
CompletionResponse::List(_) => panic!("test failed"),
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
schema Name:
name: str

schema Person:
name: Name

p = Person{
name: Name{
name: "a"
}
}

p.
2 changes: 1 addition & 1 deletion kclvm/tools/src/LSP/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1314,7 +1314,7 @@ fn konfig_completion_test_main() {

let expected_labels: Vec<String> = ["Job", "Server"]
.iter()
.map(|attr| format!("{}{}", attr, "{}"))
.map(|attr| attr.to_string())
.collect();
assert_eq!(got_labels, expected_labels);

Expand Down
22 changes: 21 additions & 1 deletion kclvm/tools/src/LSP/src/util.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use indexmap::IndexSet;
use kclvm_ast::ast::{
ConfigEntry, Expr, Identifier, Node, NodeRef, PosTuple, Program, SchemaStmt, Stmt, Type,
ConfigEntry, Expr, Identifier, Node, NodeRef, PosTuple, Program, SchemaExpr, SchemaStmt, Stmt,
Type,
};
use kclvm_ast::pos::ContainsPos;

Expand Down Expand Up @@ -595,6 +596,25 @@ fn inner_most_expr_in_config_entry(
}
}

pub(crate) fn is_in_schema_expr(
program: &Program,
pos: &KCLPos,
) -> Option<(Node<Stmt>, SchemaExpr)> {
match program.pos_to_stmt(pos) {
Some(node) => {
let parent_expr = inner_most_expr_in_stmt(&node.node, pos, None).1;
match parent_expr {
Some(expr) => match expr.node {
Expr::Schema(schema) => Some((node, schema)),
_ => None,
},
None => None,
}
}
None => None,
}
}

pub(crate) fn is_in_docstring(
program: &Program,
pos: &KCLPos,
Expand Down

0 comments on commit e226b9a

Please sign in to comment.