Skip to content

Commit

Permalink
feat: syntax highlighting for hover content
Browse files Browse the repository at this point in the history
Signed-off-by: shruti2522 <[email protected]>

fmt check

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

kcl formatting

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

fmt check

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

updated test cases

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

fmt check

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

feat: syntax highlighting for hover content

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

updated tests

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

updated tests

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

test check

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

feat: syntax highlighting for hover content

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

add markup

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

fmt check

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

resolved func formatting error

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

updated test cases

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

updated tests

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

feat: syntax highlighting for hover content

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

updated test cases for tests.rs

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

feat: syntax highlighting for hover content

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

syntax highlighting with LanguageString

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

fmt check

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

updated tests

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

fmt check

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

fmt check

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

feat: syntax highlighting for hover content

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

updated test case

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

updated tests.rs

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

feat: syntax highlighting for hover content

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

fmt check

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

fixed ci

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

add pkgpath without override

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

updated completion.rs

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

updated tests.rs

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

feat: syntax highlighting for hover content

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

updated doc style

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

fix ci

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

updated comment

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

added indentation for attrs

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

fix ci

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

merge schema attr docs

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

feat: syntax highlighting for hover content

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

update hover def comment

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

updated tests

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

feat: syntax highlighting for hover content

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

fix ci

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

render doc at end

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

fix ci

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

removed additional def

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

feat: syntax highlighting for hover content

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

fix ci

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

fix dict_key_in_schema test

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

merged rest_sign and attr

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

fixed ci

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

fmt check

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

feat: syntax highlighting for hover content

Signed-off-by: shruti2522 <[email protected]>
  • Loading branch information
shruti2522 committed May 21, 2024
1 parent 00807ce commit 4cda335
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 89 deletions.
15 changes: 4 additions & 11 deletions kclvm/sema/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ impl SchemaType {
}
}

pub fn schema_ty_signature_str(&self) -> String {
pub fn schema_ty_signature_str(&self) -> (String, String) {
let base: String = if let Some(base) = &self.base {
format!("({})", base.name)
} else {
Expand All @@ -312,17 +312,10 @@ impl SchemaType {
.join(", ")
)
};
let params_str = if !params.is_empty() && !base.is_empty() {
format!("\\{}{}", params, base)
} else if !params.is_empty() {
format!("{}", params)
} else if !base.is_empty() {
format!("{}", base)
} else {
"".to_string()
};

format!("{}\n\nschema {}{}", self.pkgpath, self.name, params_str)
let rest_sign = format!("schema {}{}{}:", self.name, params, base);

(self.pkgpath.clone(), rest_sign)
}
}

Expand Down
8 changes: 5 additions & 3 deletions kclvm/tools/src/LSP/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,8 @@ fn schema_ty_to_value_complete_item(schema_ty: &SchemaType) -> KCLCompletionItem
);
let detail = {
let mut details = vec![];
details.push(schema_ty.schema_ty_signature_str());
let (pkgpath, rest_sign) = schema_ty.schema_ty_signature_str();
details.push(format!("{}\n\n{}", pkgpath, rest_sign));
details.push("Attributes:".to_string());
for (name, attr) in &schema_ty.attrs {
details.push(format!(
Expand Down Expand Up @@ -543,7 +544,8 @@ fn schema_ty_to_value_complete_item(schema_ty: &SchemaType) -> KCLCompletionItem
fn schema_ty_to_type_complete_item(schema_ty: &SchemaType) -> KCLCompletionItem {
let detail = {
let mut details = vec![];
details.push(schema_ty.schema_ty_signature_str());
let (pkgpath, rest_sign) = schema_ty.schema_ty_signature_str();
details.push(format!("{}\n\n{}", pkgpath, rest_sign));
details.push("Attributes:".to_string());
for (name, attr) in &schema_ty.attrs {
details.push(format!(
Expand Down Expand Up @@ -1259,7 +1261,7 @@ mod tests {
label: "Person(b){}".to_string(),
kind: Some(CompletionItemKind::CLASS),
detail: Some(
"__main__\n\nschema Person\\[b: int](Base)\nAttributes:\nc: int"
"__main__\n\nschema Person[b: int](Base):\nAttributes:\nc: int"
.to_string()
),
documentation: Some(lsp_types::Documentation::String("".to_string())),
Expand Down
157 changes: 100 additions & 57 deletions kclvm/tools/src/LSP/src/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use kclvm_sema::{
core::global_state::GlobalState,
ty::{FunctionType, ANY_TYPE_STR},
};
use lsp_types::{Hover, HoverContents, MarkedString};
use lsp_types::{Hover, HoverContents, LanguageString, MarkedString};

use crate::goto_def::find_def_with_gs;

Expand All @@ -17,6 +17,7 @@ pub(crate) fn hover(
gs: &GlobalState,
) -> Option<lsp_types::Hover> {
let mut docs: Vec<String> = vec![];
let mut pkg_path = String::new();
let def = find_def_with_gs(kcl_pos, gs, true);
match def {
Some(def_ref) => match gs.get_symbols().get_symbol(def_ref) {
Expand All @@ -27,25 +28,22 @@ pub(crate) fn hover(
// Schema Definition hover
// ```
// pkg
// schema Foo(Base)[param: type]
// schema Foo(Base)[param: type]:
// -----------------
// doc
// -----------------
// Attributes:
// attr1: type
// attr2? type
// -----------------
// doc
// ```
let schema_ty = ty.into_schema_type();
docs.push(schema_ty.schema_ty_signature_str());
if !schema_ty.doc.is_empty() {
docs.push(schema_ty.doc.clone());
}
let (pkgpath, rest_sign) = schema_ty.schema_ty_signature_str();
pkg_path = pkgpath;

// The attr of schema_ty does not contain the attrs from inherited base schema.
// Use the api provided by GlobalState to get all attrs
let module_info = gs.get_packages().get_module_info(&kcl_pos.filename);
let schema_attrs = obj.get_all_attributes(gs.get_symbols(), module_info);
let mut attrs = vec!["Attributes:".to_string()];
let mut attrs: Vec<String> = vec![];
for schema_attr in schema_attrs {
if let kclvm_sema::core::symbol::SymbolKind::Attribute =
schema_attr.get_kind()
Expand All @@ -59,14 +57,24 @@ pub(crate) fn hover(
None => ANY_TYPE_STR.to_string(),
};
attrs.push(format!(
"{}{}: {}",
"\t{}{}: {}",
name,
if attr_symbol.is_optional() { "?" } else { "" },
attr_ty_str,
));
}
}
docs.push(attrs.join("\n\n"));

let merged_doc = if !attrs.is_empty() {
format!("{}\n{}", rest_sign.clone(), attrs.join("\n"))
} else {
rest_sign.clone()
};
docs.push(merged_doc);

if !schema_ty.doc.is_empty() {
docs.push(schema_ty.doc.clone());
}
}
_ => {}
},
Expand Down Expand Up @@ -120,24 +128,33 @@ pub(crate) fn hover(
},
None => {}
}
docs_to_hover(docs)
docs_to_hover(docs, pkg_path)
}

// Convert docs to Hover. This function will convert to
// None, Scalar or Array according to the number of positions
fn docs_to_hover(docs: Vec<String>) -> Option<lsp_types::Hover> {
match docs.len() {
fn docs_to_hover(docs: Vec<String>, pkg_path: String) -> Option<lsp_types::Hover> {
let mut all_docs = Vec::new();

if !pkg_path.is_empty() {
all_docs.push(MarkedString::String(pkg_path));
}

all_docs.extend(docs.iter().map(|doc| {
MarkedString::LanguageString(LanguageString {
language: "KCL".to_owned(),
value: doc.clone(),
})
}));

match all_docs.len() {
0 => None,
1 => Some(Hover {
contents: HoverContents::Scalar(MarkedString::String(docs[0].clone())),
contents: HoverContents::Scalar(all_docs.remove(0)),
range: None,
}),
_ => Some(Hover {
contents: HoverContents::Array(
docs.iter()
.map(|doc| MarkedString::String(doc.clone()))
.collect(),
),
contents: HoverContents::Array(all_docs),
range: None,
}),
}
Expand Down Expand Up @@ -186,7 +203,7 @@ mod tests {
use std::path::PathBuf;

use kclvm_error::Position as KCLPos;
use lsp_types::MarkedString;
use lsp_types::{LanguageString, MarkedString};
use proc_macro_crate::bench_test;

use crate::tests::compile_test_file;
Expand All @@ -213,13 +230,13 @@ mod tests {
match got.contents {
lsp_types::HoverContents::Array(vec) => {
if let MarkedString::String(s) = vec[0].clone() {
assert_eq!(s, "pkg\n\nschema Person");
assert_eq!(s, "pkg");
}
if let MarkedString::String(s) = vec[1].clone() {
assert_eq!(s, "hover doc test");
assert_eq!(s, "schema Person:");
}
if let MarkedString::String(s) = vec[2].clone() {
assert_eq!(s, "Attributes:\n\nname: str\n\nage: int");
assert_eq!(s, "\tname: str\n\tage: int");
}
}
_ => unreachable!("test error"),
Expand Down Expand Up @@ -251,25 +268,34 @@ mod tests {
];

// When converting to hover content
let hover = docs_to_hover(docs.clone());
let hover = docs_to_hover(docs.clone(), "".to_string());

// Then the result should be a Hover object with an Array of MarkedString::String
// Then the result should be a Hover object with an Array of MarkedString::LanguageString
assert!(hover.is_some());
let hover = hover.unwrap();
match hover.contents {
lsp_types::HoverContents::Array(vec) => {
assert_eq!(vec.len(), 3);
assert_eq!(
vec[0],
MarkedString::String("Documentation string 1".to_string())
MarkedString::LanguageString(LanguageString {
language: "KCL".to_string(),
value: "Documentation string 1".to_string()
})
);
assert_eq!(
vec[1],
MarkedString::String("Documentation string 2".to_string())
MarkedString::LanguageString(LanguageString {
language: "KCL".to_string(),
value: "Documentation string 2".to_string()
})
);
assert_eq!(
vec[2],
MarkedString::String("Documentation string 3".to_string())
MarkedString::LanguageString(LanguageString {
language: "KCL".to_string(),
value: "Documentation string 3".to_string()
})
);
}
_ => panic!("Unexpected hover contents"),
Expand All @@ -291,13 +317,13 @@ mod tests {
match got.contents {
lsp_types::HoverContents::Array(vec) => {
if let MarkedString::String(s) = vec[0].clone() {
assert_eq!(s, "__main__\n\nschema Person");
assert_eq!(s, "__main__");
}
if let MarkedString::String(s) = vec[1].clone() {
assert_eq!(s, "hover doc test");
assert_eq!(s, "schema Person:\n\tname: str\n\tage?: int");
}
if let MarkedString::String(s) = vec[2].clone() {
assert_eq!(s, "Attributes:\n\nname: str\n\nage?: int");
assert_eq!(s, "hover doc test");
}
}
_ => unreachable!("test error"),
Expand All @@ -319,10 +345,7 @@ mod tests {
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");
assert_eq!(s, "name: str\nname doc test");
}
}
_ => unreachable!("test error"),
Expand All @@ -338,10 +361,7 @@ mod tests {
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");
assert_eq!(s, "age: int\nage doc test");
}
}
_ => unreachable!("test error"),
Expand All @@ -363,10 +383,7 @@ mod tests {
match got.contents {
lsp_types::HoverContents::Array(vec) => {
if let MarkedString::String(s) = vec[0].clone() {
assert_eq!(s, "fn f(x: any) -> any");
}
if let MarkedString::String(s) = vec[1].clone() {
assert_eq!(s, "lambda documents");
assert_eq!(s, "fn f(x: any) -> any\nlambda documents");
}
}
_ => unreachable!("test error"),
Expand Down Expand Up @@ -526,10 +543,10 @@ mod tests {
lsp_types::HoverContents::Array(vec) => {
assert_eq!(vec.len(), 2);
if let MarkedString::String(s) = vec[0].clone() {
assert_eq!(s, "fib\n\nschema Fib");
assert_eq!(s, "fib");
}
if let MarkedString::String(s) = vec[1].clone() {
assert_eq!(s, "Attributes:\n\nn: int\n\nvalue: int");
assert_eq!(s, "schema Fib:\n\tn: int\n\tvalue: int");
}
}
_ => unreachable!("test error"),
Expand Down Expand Up @@ -586,11 +603,16 @@ mod tests {
column: Some(1),
};
let got = hover(&program, &pos, &gs).unwrap();
let expect_content = vec![MarkedString::String(
"fn deprecated(version: str, reason: str, strict: bool) -> any".to_string(),
), MarkedString::String(
"This decorator is used to get the deprecation message according to the wrapped key-value pair.".to_string(),
)];
let expect_content = vec![
MarkedString::LanguageString(LanguageString {
language: "KCL".to_string(),
value: "fn deprecated(version: str, reason: str, strict: bool) -> any".to_string(),
}),
MarkedString::LanguageString(LanguageString {
language: "KCL".to_string(),
value: "This decorator is used to get the deprecation message according to the wrapped key-value pair.".to_string(),
}),
];
match got.contents {
lsp_types::HoverContents::Array(vec) => {
assert_eq!(vec, expect_content)
Expand Down Expand Up @@ -624,8 +646,11 @@ mod tests {
let got = hover(&program, &pos, &gs).unwrap();

let expect_content = vec![
MarkedString::String("__main__\n\nschema Data1\\[m: {str:str}](Data)".to_string()),
MarkedString::String("Attributes:\n\nname: str\n\nage: int".to_string()),
MarkedString::String("__main__".to_string()),
MarkedString::LanguageString(LanguageString {
language: "KCL".to_string(),
value: "schema Data1[m: {str:str}](Data):\n\tname: str\n\tage: int".to_string(),
}),
];

match got.contents {
Expand All @@ -647,22 +672,40 @@ mod tests {
column: Some(5),
};
let got = hover(&program, &pos, &gs).unwrap();
insta::assert_snapshot!(format!("{:?}", got));

match got.contents {
lsp_types::HoverContents::Scalar(marked_string) => {
if let MarkedString::String(s) = marked_string {
assert_eq!(s, "name: int");
}
}
_ => unreachable!("test error"),
}

let pos = KCLPos {
filename: file.clone(),
line: 9,
column: Some(5),
};
let got = hover(&program, &pos, &gs).unwrap();
insta::assert_snapshot!(format!("{:?}", got));
let expected =
lsp_types::HoverContents::Scalar(MarkedString::LanguageString(LanguageString {
language: "KCL".to_string(),
value: "name: int".to_string(),
}));
assert_eq!(got.contents, expected);

let pos = KCLPos {
filename: file.clone(),
line: 13,
column: Some(5),
};
let got = hover(&program, &pos, &gs).unwrap();
insta::assert_snapshot!(format!("{:?}", got));
let expected =
lsp_types::HoverContents::Scalar(MarkedString::LanguageString(LanguageString {
language: "KCL".to_string(),
value: "name: int".to_string(),
}));
assert_eq!(got.contents, expected);
}
}
Loading

0 comments on commit 4cda335

Please sign in to comment.