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 <shruti.apc01@gmail.com>

fmt check

Signed-off-by: shruti2522 <shruti.apc01@gmail.com>

kcl formatting

Signed-off-by: shruti2522 <shruti.apc01@gmail.com>

fmt check

Signed-off-by: shruti2522 <shruti.apc01@gmail.com>

updated test cases

Signed-off-by: shruti2522 <shruti.apc01@gmail.com>

fmt check

Signed-off-by: shruti2522 <shruti.apc01@gmail.com>

feat: syntax highlighting for hover content

Signed-off-by: shruti2522 <shruti.apc01@gmail.com>

updated tests

Signed-off-by: shruti2522 <shruti.apc01@gmail.com>

updated tests

Signed-off-by: shruti2522 <shruti.apc01@gmail.com>

test check

Signed-off-by: shruti2522 <shruti.apc01@gmail.com>

feat: syntax highlighting for hover content

Signed-off-by: shruti2522 <shruti.apc01@gmail.com>

add markup

Signed-off-by: shruti2522 <shruti.apc01@gmail.com>

fmt check

Signed-off-by: shruti2522 <shruti.apc01@gmail.com>

resolved func formatting error

Signed-off-by: shruti2522 <shruti.apc01@gmail.com>

updated test cases

Signed-off-by: shruti2522 <shruti.apc01@gmail.com>

updated tests

Signed-off-by: shruti2522 <shruti.apc01@gmail.com>

feat: syntax highlighting for hover content

Signed-off-by: shruti2522 <shruti.apc01@gmail.com>
  • Loading branch information
shruti2522 committed May 19, 2024
1 parent 86f4a82 commit 31ee8c3
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 60 deletions.
14 changes: 4 additions & 10 deletions kclvm/sema/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub use unify::*;
pub use walker::walk_type;

use super::resolver::doc::Example;
use kclvm_utils::markup::add_markup;

#[cfg(test)]
mod tests;
Expand Down Expand Up @@ -312,17 +313,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 schema_str = add_markup(&format!("schema {}{}{}", self.name, params, base));

format!("{}\n\n{}", self.pkgpath, schema_str)
}
}

Expand Down
2 changes: 1 addition & 1 deletion kclvm/tools/src/LSP/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1259,7 +1259,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\n```kcl\nschema Person[b: int](Base)\n```\nAttributes:\nc: int"
.to_string()
),
documentation: Some(lsp_types::Documentation::String("".to_string())),
Expand Down
93 changes: 51 additions & 42 deletions kclvm/tools/src/LSP/src/hover.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use crate::goto_def::find_def_with_gs;
use kclvm_ast::ast::Program;
use kclvm_error::Position as KCLPos;
use kclvm_sema::{
builtin::BUILTIN_DECORATORS,
core::global_state::GlobalState,
ty::{FunctionType, ANY_TYPE_STR},
};
use kclvm_utils::markup::add_markup;
use lsp_types::{Hover, HoverContents, MarkedString};

use crate::goto_def::find_def_with_gs;

/// Returns a short text describing element at position.
/// Specifically, the doc for schema and schema attr(todo)
pub(crate) fn hover(
Expand Down Expand Up @@ -45,7 +45,7 @@ pub(crate) fn hover(
// 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!["**Attributes:**".to_string()];
for schema_attr in schema_attrs {
if let kclvm_sema::core::symbol::SymbolKind::Attribute =
schema_attr.get_kind()
Expand All @@ -58,12 +58,13 @@ pub(crate) fn hover(
Some(ty) => ty.ty_str(),
None => ANY_TYPE_STR.to_string(),
};
attrs.push(format!(
let formatted_attr = format!(
"{}{}: {}",
name,
if attr_symbol.is_optional() { "?" } else { "" },
attr_ty_str,
));
);
attrs.push(add_markup(&formatted_attr));
}
}
docs.push(attrs.join("\n\n"));
Expand All @@ -74,7 +75,7 @@ pub(crate) fn hover(
let sema_info = obj.get_sema_info();
match &sema_info.ty {
Some(ty) => {
docs.push(format!("{}: {}", &obj.get_name(), ty.ty_str()));
docs.push(add_markup(&format!("{}: {}", &obj.get_name(), ty.ty_str())));
if let Some(doc) = &sema_info.doc {
if !doc.is_empty() {
docs.push(doc.clone());
Expand All @@ -90,7 +91,7 @@ pub(crate) fn hover(
docs.extend(build_func_hover_content(func_ty, obj.get_name().clone()));
}
_ => {
docs.push(format!("{}: {}", &obj.get_name(), ty.ty_str()));
docs.push(add_markup(&format!("{}: {}", &obj.get_name(), ty.ty_str())));
}
},
_ => {}
Expand All @@ -113,7 +114,7 @@ pub(crate) fn hover(
Some(ty) => ty.ty_str(),
None => "".to_string(),
};
docs.push(format!("{}: {}", &obj.get_name(), ty_str));
docs.push(add_markup(&format!("{}: {}", &obj.get_name(), ty_str)));
}
},
None => {}
Expand Down Expand Up @@ -144,34 +145,29 @@ fn docs_to_hover(docs: Vec<String>) -> Option<lsp_types::Hover> {
}

// Build hover content for function call
// ```
// pkg
// -----------------
// function func_name(arg1: type, arg2: type, ..) -> type
// -----------------
// doc
// ```
fn build_func_hover_content(func_ty: &FunctionType, name: String) -> Vec<String> {
let mut docs = vec![];
if let Some(ty) = &func_ty.self_ty {
let self_ty = format!("{}\n\n", ty.ty_str());
let self_ty = add_markup(&format!("{}\n\n", ty.ty_str()));
docs.push(self_ty);
}

let mut sig = format!("fn {}(", name);
let func_str = add_markup(&format!("fn {}", name));
let mut sig = format!("{}(", func_str);
if func_ty.params.is_empty() {
sig.push(')');
} else {
for (i, p) in func_ty.params.iter().enumerate() {
sig.push_str(&format!("{}: {}", p.name, p.ty.ty_str()));
let p_str = &format!("{}: {}", p.name, p.ty.ty_str());
sig.push_str(&add_markup(&p_str));

if i != func_ty.params.len() - 1 {
sig.push_str(", ");
}
}
sig.push(')');
}
sig.push_str(&format!(" -> {}", func_ty.return_ty.ty_str()));
let func_ty_str = &format!(" -> {}", func_ty.return_ty.ty_str());
sig.push_str(&add_markup(&func_ty_str));
docs.push(sig);

if !func_ty.doc.is_empty() {
Expand Down Expand Up @@ -213,13 +209,16 @@ 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\n\n```kcl\nschema Person\n```");
}
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\nname: str\n\nage: int");
assert_eq!(
s,
"**Attributes:**\n\n```kcl\nname: str\n```\n\n```kcl\nage: int\n```"
);
}
}
_ => unreachable!("test error"),
Expand All @@ -233,7 +232,7 @@ mod tests {
match got.contents {
lsp_types::HoverContents::Scalar(marked_string) => {
if let MarkedString::String(s) = marked_string {
assert_eq!(s, "name: str");
assert_eq!(s, "```kcl\nname: str\n```");
}
}
_ => unreachable!("test error"),
Expand Down Expand Up @@ -291,13 +290,16 @@ 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__\n\n```kcl\nschema Person\n```");
}
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\nname: str\n\nage?: int");
assert_eq!(
s,
"**Attributes:**\n\n```kcl\nname: str\n```\n\n```kcl\nage?: int\n```"
);
}
}
_ => unreachable!("test error"),
Expand All @@ -319,7 +321,7 @@ mod tests {
match got.contents {
lsp_types::HoverContents::Array(vec) => {
if let MarkedString::String(s) = vec[0].clone() {
assert_eq!(s, "name: str");
assert_eq!(s, "```kcl\nname: str\n```");
}
if let MarkedString::String(s) = vec[1].clone() {
assert_eq!(s, "name doc test");
Expand All @@ -338,7 +340,7 @@ mod tests {
match got.contents {
lsp_types::HoverContents::Array(vec) => {
if let MarkedString::String(s) = vec[0].clone() {
assert_eq!(s, "age: int");
assert_eq!(s, "```kcl\nage: int\n```");
}
if let MarkedString::String(s) = vec[1].clone() {
assert_eq!(s, "age doc test");
Expand All @@ -364,7 +366,7 @@ mod tests {
lsp_types::HoverContents::Array(vec) => {
assert_eq!(vec.len(), 2);
if let MarkedString::String(s) = vec[0].clone() {
assert_eq!(s, "fn encode(value: str, encoding: str) -> str");
assert_eq!(s, "```kcl\nfn encode\n```(```kcl\nvalue: str\n```, ```kcl\nencoding: str\n```)```kcl\n -> str\n```");
}
if let MarkedString::String(s) = vec[1].clone() {
assert_eq!(
Expand All @@ -387,10 +389,10 @@ mod tests {
lsp_types::HoverContents::Array(vec) => {
assert_eq!(vec.len(), 3);
if let MarkedString::String(s) = vec[0].clone() {
assert_eq!(s, "str\n\n");
assert_eq!(s, "```kcl\nstr\n\n\n```");
}
if let MarkedString::String(s) = vec[1].clone() {
assert_eq!(s, "fn count(sub: str, start: int, end: int) -> int");
assert_eq!(s, "```kcl\nfn count\n```(```kcl\nsub: str\n```, ```kcl\nstart: int\n```, ```kcl\nend: int\n```)```kcl\n -> int\n```");
}
if let MarkedString::String(s) = vec[2].clone() {
assert_eq!(s, "Return the number of non-overlapping occurrences of substring sub in the range [start, end]. Optional arguments start and end are interpreted as in slice notation.");
Expand All @@ -410,7 +412,7 @@ mod tests {
lsp_types::HoverContents::Array(vec) => {
assert_eq!(vec.len(), 2);
if let MarkedString::String(s) = vec[0].clone() {
assert_eq!(s, "fn print() -> NoneType");
assert_eq!(s, "```kcl\nfn print\n```()```kcl\n -> NoneType\n```");
}
if let MarkedString::String(s) = vec[1].clone() {
assert_eq!(s, "Prints the values to a stream, or to the system stdout by default.\n\nOptional keyword arguments:\n\nsep: string inserted between values, default a space.\n\nend: string appended after the last value, default a newline.");
Expand All @@ -433,7 +435,7 @@ mod tests {
match got.contents {
lsp_types::HoverContents::Scalar(marked_string) => {
if let MarkedString::String(s) = marked_string {
assert_eq!(s, "value: int");
assert_eq!(s, "```kcl\nvalue: int\n```");
}
}
_ => unreachable!("test error"),
Expand All @@ -453,7 +455,7 @@ mod tests {
match got.contents {
lsp_types::HoverContents::Scalar(marked_string) => {
if let MarkedString::String(s) = marked_string {
assert_eq!(s, "result: {str:str}");
assert_eq!(s, "```kcl\nresult: {str:str}\n```");
}
}
_ => unreachable!("test error"),
Expand All @@ -474,10 +476,10 @@ mod tests {
lsp_types::HoverContents::Array(vec) => {
assert_eq!(vec.len(), 3);
if let MarkedString::String(s) = vec[0].clone() {
assert_eq!(s, "str\n\n");
assert_eq!(s, "```kcl\nstr\n\n\n```");
}
if let MarkedString::String(s) = vec[1].clone() {
assert_eq!(s, "fn capitalize() -> str");
assert_eq!(s, "```kcl\nfn capitalize\n```()```kcl\n -> str\n```");
}
if let MarkedString::String(s) = vec[2].clone() {
assert_eq!(s, "Return a copy of the string with its first character capitalized and the rest lowercased.");
Expand All @@ -501,10 +503,13 @@ 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\n\n```kcl\nschema Fib\n```");
}
if let MarkedString::String(s) = vec[1].clone() {
assert_eq!(s, "Attributes:\n\nn: int\n\nvalue: int");
assert_eq!(
s,
"**Attributes:**\n\n```kcl\nn: int\n```\n\n```kcl\nvalue: int\n```"
);
}
}
_ => unreachable!("test error"),
Expand All @@ -524,7 +529,7 @@ mod tests {
match got.contents {
lsp_types::HoverContents::Scalar(marked_string) => {
if let MarkedString::String(s) = marked_string {
assert_eq!(s, "stratege: str");
assert_eq!(s, "```kcl\nstratege: str\n```");
}
}
_ => unreachable!("test error"),
Expand All @@ -544,7 +549,7 @@ mod tests {
match got.contents {
lsp_types::HoverContents::Scalar(marked_string) => {
if let MarkedString::String(s) = marked_string {
assert_eq!(s, "n1: int");
assert_eq!(s, "```kcl\nn1: int\n```");
}
}
_ => unreachable!("test error"),
Expand All @@ -562,7 +567,7 @@ mod tests {
};
let got = hover(&program, &pos, &gs).unwrap();
let expect_content = vec![MarkedString::String(
"fn deprecated(version: str, reason: str, strict: bool) -> any".to_string(),
"```kcl\nfn deprecated\n```(```kcl\nversion: str\n```, ```kcl\nreason: str\n```, ```kcl\nstrict: bool\n```)```kcl\n -> any\n```".to_string(),
), MarkedString::String(
"This decorator is used to get the deprecation message according to the wrapped key-value pair.".to_string(),
)];
Expand Down Expand Up @@ -599,8 +604,12 @@ 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__\n\n```kcl\nschema Data1[m: {str:str}](Data)\n```".to_string(),
),
MarkedString::String(
"**Attributes:**\n\n```kcl\nname: str\n```\n\n```kcl\nage: int\n```".to_string(),
),
];

match got.contents {
Expand Down
19 changes: 12 additions & 7 deletions kclvm/tools/src/LSP/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1169,9 +1169,12 @@ fn hover_test() {
res.result.unwrap(),
to_json(Hover {
contents: HoverContents::Array(vec![
MarkedString::String("__main__\n\nschema Person".to_string()),
MarkedString::String("__main__\n\n```kcl\nschema Person\n```".to_string()),
MarkedString::String("hover doc test".to_string()),
MarkedString::String("Attributes:\n\nname: str\n\nage?: int".to_string()),
MarkedString::String(
"```kcl\nAttributes:\n```\n\n```kcl\nname: str\n```\n\n```kcl\nage?: int\n```"
.to_string()
),
]),
range: None
})
Expand Down Expand Up @@ -1225,7 +1228,9 @@ fn hover_assign_in_lambda_test() {
assert_eq!(
res.result.unwrap(),
to_json(Hover {
contents: HoverContents::Scalar(MarkedString::String("images: [str]".to_string()),),
contents: HoverContents::Scalar(MarkedString::String(
"```kcl\nimages: [str]\n```".to_string()
),),
range: None
})
.unwrap()
Expand Down Expand Up @@ -1663,9 +1668,9 @@ fn konfig_hover_test_main() {
let got = hover(&program, &pos, &gs).unwrap();
match got.contents {
HoverContents::Array(arr) => {
let expect: Vec<MarkedString> = ["base.pkg.kusion_models.kube.frontend\n\nschema Server",
let expect: Vec<MarkedString> = ["base.pkg.kusion_models.kube.frontend\n\n```kcl\nschema Server\n```",
"Server is abstaction of Deployment and StatefulSet.",
"Attributes:\n\nname?: str\n\nworkloadType: str(Deployment) | str(StatefulSet)\n\nrenderType?: str(Server) | str(KubeVelaApplication)\n\nreplicas: int\n\nimage: str\n\nschedulingStrategy: SchedulingStrategy\n\nmainContainer: Main\n\nsidecarContainers?: [Sidecar]\n\ninitContainers?: [Sidecar]\n\nuseBuiltInLabels?: bool\n\nlabels?: {str:str}\n\nannotations?: {str:str}\n\nuseBuiltInSelector?: bool\n\nselector?: {str:str}\n\npodMetadata?: ObjectMeta\n\nvolumes?: [Volume]\n\nneedNamespace?: bool\n\nenableMonitoring?: bool\n\nconfigMaps?: [ConfigMap]\n\nsecrets?: [Secret]\n\nservices?: [Service]\n\ningresses?: [Ingress]\n\nserviceAccount?: ServiceAccount\n\nstorage?: ObjectStorage\n\ndatabase?: DataBase"]
"```kcl\nAttributes:\n```\n\n```kcl\nname?: str\n```\n\n```kcl\nworkloadType: str(Deployment) | str(StatefulSet)\n```\n\n```kcl\nrenderType?: str(Server) | str(KubeVelaApplication)\n```\n\n```kcl\nreplicas: int\n```\n\n```kcl\nimage: str\n```\n\n```kcl\nschedulingStrategy: SchedulingStrategy\n```\n\n```kcl\nmainContainer: Main\n```\n\n```kcl\nsidecarContainers?: [Sidecar]\n```\n\n```kcl\ninitContainers?: [Sidecar]\n```\n\n```kcl\nuseBuiltInLabels?: bool\n```\n\n```kcl\nlabels?: {str:str}\n```\n\n```kcl\nannotations?: {str:str}\n```\n\n```kcl\nuseBuiltInSelector?: bool\n```\n\n```kcl\nselector?: {str:str}\n```\n\n```kcl\npodMetadata?: ObjectMeta\n```\n\n```kcl\nvolumes?: [Volume]\n```\n\n```kcl\nneedNamespace?: bool\n```\n\n```kcl\nenableMonitoring?: bool\n```\n\n```kcl\nconfigMaps?: [ConfigMap]\n```\n\n```kcl\nsecrets?: [Secret]\n```\n\n```kcl\nservices?: [Service]\n```\n\n```kcl\ningresses?: [Ingress]\n```\n\n```kcl\nserviceAccount?: ServiceAccount\n```\n\n```kcl\nstorage?: ObjectStorage\n```\n\n```kcl\ndatabase?: DataBase\n```"]
.iter()
.map(|s| MarkedString::String(s.to_string()))
.collect();
Expand All @@ -1684,7 +1689,7 @@ fn konfig_hover_test_main() {
match got.contents {
HoverContents::Array(arr) => {
let expect: Vec<MarkedString> = [
"schedulingStrategy: SchedulingStrategy",
"```kcl\nschedulingStrategy: SchedulingStrategy\n```",
"SchedulingStrategy represents scheduling strategy.",
]
.iter()
Expand All @@ -1706,7 +1711,7 @@ fn konfig_hover_test_main() {
HoverContents::Scalar(s) => {
assert_eq!(
s,
MarkedString::String("appConfiguration: Server".to_string())
MarkedString::String("```kcl\nappConfiguration: Server\n```".to_string())
);
}
_ => unreachable!("test error"),
Expand Down
1 change: 1 addition & 0 deletions kclvm/utils/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod fslock;
pub mod markup;
pub mod path;
pub mod pkgpath;
Loading

0 comments on commit 31ee8c3

Please sign in to comment.