Skip to content

Commit

Permalink
arch: migrate lsp newline complete to new sema model (kcl-lang#889)
Browse files Browse the repository at this point in the history
* arch: migrate lsp newline complete to new sema model

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

* test: sort result in ut

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

---------

Signed-off-by: he1pa <[email protected]>
  • Loading branch information
He1pa authored Nov 16, 2023
1 parent e61efe8 commit 68b1f8b
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 52 deletions.
101 changes: 59 additions & 42 deletions kclvm/tools/src/LSP/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ pub(crate) fn completion(
Some(c) => match c {
'.' => completion_dot(program, pos, prog_scope, gs),
'=' | ':' => completion_assign(pos, gs),
'\n' => completion_newline(program, pos, prog_scope),
'\n' => completion_newline(program, pos, prog_scope, gs),
_ => None,
},
None => {
Expand Down Expand Up @@ -304,51 +304,66 @@ fn completion_assign(pos: &KCLPos, gs: &GlobalState) -> Option<lsp_types::Comple
fn completion_newline(
program: &Program,
pos: &KCLPos,
prog_scope: &ProgramScope,
_prog_scope: &ProgramScope,
gs: &GlobalState,
) -> Option<lsp_types::CompletionResponse> {
let mut completions: IndexSet<KCLCompletionItem> = IndexSet::new();
let pos = &KCLPos {
filename: pos.filename.clone(),
line: pos.line - 1,
column: pos.column,
};

match program.pos_to_stmt(pos) {
Some(node) => {
let end_pos = node.get_end_pos();
if let Some((node, schema_expr)) = is_in_schema_expr(program, &end_pos) {
let schema_def = find_def(node, &schema_expr.name.get_end_pos(), prog_scope);
if let Some(schema) = schema_def {
if let Definition::Object(obj, _) = schema {
let schema_type = obj.ty.into_schema_type();
completions.extend(schema_type.attrs.iter().map(|(name, attr)| {
KCLCompletionItem {
label: name.clone(),
detail: Some(format!("{}: {}", name, attr.ty.ty_str())),
documentation: attr.doc.clone(),
kind: Some(KCLCompletionItemKind::SchemaAttr),
if let Some((doc, schema)) = is_in_docstring(program, &pos) {
let doc = parse_doc_string(&doc.node);
if doc.summary.is_empty() && doc.attrs.len() == 0 && doc.examples.len() == 0 {
// empty docstring, provide total completion
let doc_parsed = Doc::new_from_schema_stmt(&schema);
let label = doc_parsed.to_doc_string();
// generate docstring from doc
completions.insert(KCLCompletionItem {
label,
detail: Some("generate docstring".to_string()),
documentation: Some(format!("docstring for {}", schema.name.node.clone())),
kind: Some(KCLCompletionItemKind::Doc),
});
}
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: match &sema_info.ty {
Some(ty) => Some(format!("{}: {}", name, ty.ty_str())),
None => None,
},
documentation: match &sema_info.doc {
Some(doc) => {
if doc.is_empty() {
None
} else {
Some(doc.clone())
}
}
None => None,
},
kind: Some(KCLCompletionItemKind::SchemaAttr),
});
}
}));
_ => {}
}
}
}
} else if let Some((doc, schema)) = is_in_docstring(program, &pos) {
let doc = parse_doc_string(&doc.node);
if doc.summary.is_empty() && doc.attrs.len() == 0 && doc.examples.len() == 0 {
// empty docstring, provide total completion
let doc_parsed = Doc::new_from_schema_stmt(&schema);
let label = doc_parsed.to_doc_string();
// generate docstring from doc
completions.insert(KCLCompletionItem {
label,
detail: Some("generate docstring".to_string()),
documentation: Some(format!("docstring for {}", schema.name.node.clone())),
kind: Some(KCLCompletionItemKind::Doc),
});
None => {}
}
}
}
None => {}
}

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

Expand Down Expand Up @@ -1054,11 +1069,12 @@ mod tests {
column: Some(4),
};

let got = completion(Some('\n'), &program, &pos, &prog_scope, &gs).unwrap();
match got {
let mut got = completion(Some('\n'), &program, &pos, &prog_scope, &gs).unwrap();
match &mut got {
CompletionResponse::Array(arr) => {
arr.sort_by(|a, b| a.label.cmp(&b.label));
assert_eq!(
arr[0],
arr[1],
CompletionItem {
label: "c".to_string(),
kind: Some(CompletionItemKind::FIELD),
Expand All @@ -1084,9 +1100,10 @@ mod tests {
column: Some(4),
};

let got = completion(Some('\n'), &program, &pos, &prog_scope, &gs).unwrap();
match got {
let mut got = completion(Some('\n'), &program, &pos, &prog_scope, &gs).unwrap();
match &mut got {
CompletionResponse::Array(arr) => {
arr.sort_by(|a, b| a.label.cmp(&b.label));
assert_eq!(
arr[0],
CompletionItem {
Expand Down
17 changes: 9 additions & 8 deletions kclvm/tools/src/LSP/src/request.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use anyhow::{anyhow, Ok};
use crossbeam_channel::Sender;
use kclvm_ast::pos::GetPos;
use kclvm_sema::info::is_valid_kcl_name;
use lsp_types::{Location, TextEdit};
use ra_ap_vfs::VfsPath;
Expand All @@ -17,6 +18,7 @@ use crate::{
goto_def::goto_definition_with_gs,
hover, quick_fix,
state::{log_message, LanguageServerSnapshot, LanguageServerState, Task},
util::{parse_param_and_compile, Param},
};

impl LanguageServerState {
Expand Down Expand Up @@ -194,19 +196,18 @@ pub(crate) fn handle_completion(
if !snapshot.verify_request_path(&path.clone().into(), &sender) {
return Ok(None);
}
let db = snapshot.get_db(&path.clone().into())?;

let db =
parse_param_and_compile(Param { file: file.clone() }, Some(snapshot.vfs.clone())).unwrap();

let kcl_pos = kcl_pos(&file, params.text_document_position.position);
let completion_trigger_character = params
.context
.and_then(|ctx| ctx.trigger_character)
.and_then(|s| s.chars().next());
let res = completion(
completion_trigger_character,
&db.prog,
&kcl_pos,
&db.scope,
&db.gs,
);

let res = completion(completion_trigger_character, &db.0, &kcl_pos, &db.1, &db.3);

if res.is_none() {
log_message("Completion item not found".to_string(), &sender)?;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
schema Server:
""""""
"""
"""
name: str
workloadType: "Deployment" | "StatefulSet"
replica: int = 1
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ schema Base:
schema Person[b: int](Base):
c: int

p1= Person(b){}
p1= Person(b){

}

0 comments on commit 68b1f8b

Please sign in to comment.