Skip to content

Commit

Permalink
fix: fix lsp completion. 1.dot completion of schema attr with schema …
Browse files Browse the repository at this point in the history
…type 2. newline completion of schema attr when cursor in schemastmt

Signed-off-by: he1pa <[email protected]>
  • Loading branch information
He1pa committed Nov 28, 2023
1 parent 85d93a8 commit d97e1d8
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 45 deletions.
127 changes: 83 additions & 44 deletions kclvm/tools/src/LSP/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use kclvm_sema::resolver::scope::ProgramScope;
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 @@ -158,11 +158,12 @@ fn completion_dot(
) -> Option<lsp_types::CompletionResponse> {
let mut items: IndexSet<KCLCompletionItem> = IndexSet::new();
// get pre position of trigger character '.'
let pre_pos = KCLPos {
filename: pos.filename.clone(),
line: pos.line,
column: pos.column.map(|c| c - 1),
};
let pre_pos =
KCLPos {
filename: pos.filename.clone(),
line: pos.line,
column: pos.column.map(|c| c - 1),
};

if let Some(stmt) = program.pos_to_stmt(&pre_pos) {
match stmt.node {
Expand Down Expand Up @@ -218,9 +219,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 @@ -332,44 +330,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 @@ -704,7 +704,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 @@ -827,7 +827,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 @@ -1032,7 +1032,6 @@ mod tests {
let (file, program, prog_scope, _, 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 @@ -1065,7 +1064,6 @@ mod tests {
let (file, program, prog_scope, _, 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 @@ -1089,14 +1087,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, prog_scope, _, 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 @@ -1185,4 +1196,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.
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,6 @@
use indexmap::IndexSet;
use kclvm_ast::ast::{
ConfigEntry, Expr, Identifier, Node, NodeRef, PosTuple, Program, SchemaStmt, Stmt, Type,
ConfigEntry, Expr, Identifier, Node, NodeRef, PosTuple, Program, SchemaStmt, Stmt, Type, SchemaExpr,
};
use kclvm_ast::pos::ContainsPos;

Expand Down Expand Up @@ -595,6 +595,26 @@ 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 d97e1d8

Please sign in to comment.