Skip to content

Commit

Permalink
Feat: enhance lsp hover. Hover for schema varibale display schema pkg…
Browse files Browse the repository at this point in the history
…, schema name, doc and attrs,for schema attr display attr name, type and doc. For other kind of variable will display variable name and type.
  • Loading branch information
He1pa committed Jul 26, 2023
1 parent fd85ed0 commit d2dd2be
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 17 deletions.
8 changes: 4 additions & 4 deletions kclvm/sema/src/resolver/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::rc::Rc;

use super::{
node::TypeRef,
scope::{ScopeKind, ScopeObject, ScopeObjectKind},
scope::{Attr::ConfigAttr, ScopeKind, ScopeObject, ScopeObjectKind},
Resolver,
};
use crate::ty::sup;
Expand Down Expand Up @@ -42,7 +42,7 @@ impl<'ctx> Resolver<'ctx> {
start,
end,
ty,
kind: ScopeObjectKind::Attribute,
kind: ScopeObjectKind::Attribute(ConfigAttr),
used: false,
doc: None,
}
Expand Down Expand Up @@ -420,7 +420,7 @@ impl<'ctx> Resolver<'ctx> {
start: key.get_pos(),
end: key.get_end_pos(),
ty: val_ty.clone(),
kind: ScopeObjectKind::Attribute,
kind: ScopeObjectKind::Attribute(ConfigAttr),
used: false,
doc: None,
},
Expand Down Expand Up @@ -454,7 +454,7 @@ impl<'ctx> Resolver<'ctx> {
start: key.get_pos(),
end: key.get_end_pos(),
ty: val_ty.clone(),
kind: ScopeObjectKind::Attribute,
kind: ScopeObjectKind::Attribute(ConfigAttr),
used: false,
doc: None,
},
Expand Down
4 changes: 2 additions & 2 deletions kclvm/sema/src/resolver/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ pub(crate) fn parse_doc_string(ori: &String) -> Doc {
}

/// The Doc struct contains a summary of schema and all the attributes described in the the docstring.
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub(crate) struct Doc {
pub summary: String,
pub attrs: Vec<Attribute>,
Expand All @@ -287,7 +287,7 @@ impl Doc {
}

/// The Attribute struct contains the attribute name and the corresponding description.
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub(crate) struct Attribute {
pub name: String,
pub desc: Vec<String>,
Expand Down
6 changes: 4 additions & 2 deletions kclvm/sema/src/resolver/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::ty::{
};

use super::format::VALID_FORMAT_SPEC_SET;
use super::scope::{ScopeKind, ScopeObject, ScopeObjectKind};
use super::scope::{Attr::SchemaAttr, SchemaAttrObj, ScopeKind, ScopeObject, ScopeObjectKind};
use super::ty::ty_str_replace_pkgpath;
use super::Resolver;

Expand Down Expand Up @@ -367,7 +367,9 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> {
start,
end,
ty: expected_ty.clone(),
kind: ScopeObjectKind::Attribute,
kind: ScopeObjectKind::Attribute(SchemaAttr(SchemaAttrObj {
option: schema_attr.is_optional,
})),
used: false,
doc: doc_str,
},
Expand Down
13 changes: 12 additions & 1 deletion kclvm/sema/src/resolver/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,24 @@ impl ContainsPos for ScopeObject {
#[derive(PartialEq, Clone, Debug)]
pub enum ScopeObjectKind {
Variable,
Attribute,
Attribute(Attr),
Definition,
Parameter,
TypeAlias,
Module(Module),
}

#[derive(PartialEq, Clone, Debug)]
pub enum Attr {
ConfigAttr,
SchemaAttr(SchemaAttrObj),
}

#[derive(PartialEq, Clone, Debug)]
pub struct SchemaAttrObj {
pub option: bool,
}

/// A scope object of module type represents an import stmt on an AST and
/// is used to record information on the AST
#[derive(PartialEq, Clone, Debug)]
Expand Down
2 changes: 1 addition & 1 deletion kclvm/tools/src/LSP/src/document_symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ fn scope_obj_to_document_symbol(obj: ScopeObject) -> DocumentSymbol {
fn scope_obj_kind_to_document_symbol_kind(kind: ScopeObjectKind) -> SymbolKind {
match kind {
ScopeObjectKind::Variable => SymbolKind::VARIABLE,
ScopeObjectKind::Attribute => SymbolKind::PROPERTY,
ScopeObjectKind::Attribute(_) => SymbolKind::PROPERTY,
ScopeObjectKind::Definition => SymbolKind::STRUCT,
ScopeObjectKind::Parameter => SymbolKind::VARIABLE,
ScopeObjectKind::TypeAlias => SymbolKind::TYPE_PARAMETER,
Expand Down
71 changes: 66 additions & 5 deletions kclvm/tools/src/LSP/src/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,75 @@ pub(crate) fn hover(
if let crate::goto_def::Definition::Object(obj) = def {
match obj.kind {
ScopeObjectKind::Definition => {
docs.insert(obj.ty.ty_str());
let doc = obj.ty.into_schema_type().doc.clone();
if !doc.is_empty() {
docs.insert(doc);
// Schema Definition hover
// ```
// pkg
// schema Foo(Base)
// -----------------
// doc
// -----------------
// Attributes:
// attr1: type
// attr2? type
// ```
let schema_ty = obj.ty.into_schema_type();
let base: String = if let Some(base) = schema_ty.base {
base.name
} else {
"".to_string()
};
docs.insert(format!(
"{}\n\nschema {}{}",
schema_ty.pkgpath, schema_ty.name, base
));
if !schema_ty.doc.is_empty() {
docs.insert(schema_ty.doc.clone());
}
let mut attrs = vec!["Attributes:".to_string()];
for (name, attr) in schema_ty.attrs {
attrs.push(format!(
"{}{}:{}",
name,
if attr.is_optional { "?" } else { "" },
format!(" {}", attr.ty.ty_str()),
));
}
docs.insert(attrs.join("\n\n"));
}
ScopeObjectKind::Attribute(attr) => match attr {
// Schema Attribute Definition hover
// ```
// attr1?: type
// ------------
// doc
// ```
kclvm_sema::resolver::scope::Attr::SchemaAttr(schema_attr) => {
docs.insert(format!(
"{}{}: {}",
obj.name,
if schema_attr.option { "?" } else { "" },
obj.ty.ty_str()
));
if let Some(doc) = obj.doc {
docs.insert(doc);
}
}
kclvm_sema::resolver::scope::Attr::ConfigAttr => {
docs.insert(format!("{}: {}", obj.name, obj.ty.ty_str()));
if let Some(doc) = obj.doc {
docs.insert(doc);
}
}
},
_ => {
docs.insert(obj.ty.ty_str());
// Variable
// ```
// name: type
//```
docs.insert(format!("{}: {}", obj.name, obj.ty.ty_str()));
if let Some(doc) = obj.doc {
docs.insert(doc);
}
}
}
}
Expand Down
18 changes: 18 additions & 0 deletions kclvm/tools/src/LSP/src/test_data/hover_test/hover.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
schema Person:
"""
hover doc test

Attributes
----------
name : str, default is False, required
name doc test
age : int, default is False, optional
age doc test
"""
name: str
age?: int

p = Person{
name: "Alice"
age: 1
}
77 changes: 75 additions & 2 deletions kclvm/tools/src/LSP/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -796,11 +796,14 @@ fn schema_doc_hover_test() {
match got.contents {
lsp_types::HoverContents::Array(vec) => {
if let MarkedString::String(s) = vec[0].clone() {
assert_eq!(s, "Person");
assert_eq!(s, "pkg\n\nschema Person");
}
if let MarkedString::String(s) = vec[1].clone() {
assert_eq!(s, "hover doc test");
}
if let MarkedString::String(s) = vec[2].clone() {
assert_eq!(s, "Attributes:\n\n__settings__?: {str:any}\n\nname: str\n\nage: int");
}
}
_ => unreachable!("test error"),
}
Expand All @@ -813,7 +816,77 @@ fn schema_doc_hover_test() {
match got.contents {
lsp_types::HoverContents::Scalar(marked_string) => {
if let MarkedString::String(s) = marked_string {
assert_eq!(s, "str");
assert_eq!(s, "name: str");
}
}
_ => unreachable!("test error"),
}
}

#[test]
fn schema_doc_hover_test1() {
let (file, program, prog_scope, _) = compile_test_file("src/test_data/hover_test/hover.k");

let pos = KCLPos {
filename: file.clone(),
line: 15,
column: Some(11),
};
let got = hover(&program, &pos, &prog_scope).unwrap();

match got.contents {
lsp_types::HoverContents::Array(vec) => {
if let MarkedString::String(s) = vec[0].clone() {
assert_eq!(s, "__main__\n\nschema Person");
}
if let MarkedString::String(s) = vec[1].clone() {
assert_eq!(s, "hover doc test");
}
if let MarkedString::String(s) = vec[2].clone() {
assert_eq!(s, "Attributes:\n\n__settings__?: {str:any}\n\nname: str\n\nage?: int");
}
}
_ => unreachable!("test error"),
}
}

#[test]
fn schema_attr_hover_test() {
let (file, program, prog_scope, _) = compile_test_file("src/test_data/hover_test/hover.k");

let pos = KCLPos {
filename: file.clone(),
line: 16,
column: Some(11),
};
let got = hover(&program, &pos, &prog_scope).unwrap();

match got.contents {
lsp_types::HoverContents::Array(vec) => {
if let MarkedString::String(s) = vec[0].clone() {
assert_eq!(s, "name: str");
}
if let MarkedString::String(s) = vec[1].clone() {
assert_eq!(s, "name doc test");
}
}
_ => unreachable!("test error"),
}

let pos = KCLPos {
filename: file.clone(),
line: 17,
column: Some(11),
};
let got = hover(&program, &pos, &prog_scope).unwrap();

match got.contents {
lsp_types::HoverContents::Array(vec) => {
if let MarkedString::String(s) = vec[0].clone() {
assert_eq!(s, "age?: int");
}
if let MarkedString::String(s) = vec[1].clone() {
assert_eq!(s, "age doc test");
}
}
_ => unreachable!("test error"),
Expand Down

0 comments on commit d2dd2be

Please sign in to comment.