diff --git a/kclvm/sema/src/ty/mod.rs b/kclvm/sema/src/ty/mod.rs index ad47f5262..c113fb533 100644 --- a/kclvm/sema/src/ty/mod.rs +++ b/kclvm/sema/src/ty/mod.rs @@ -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 { @@ -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) } } diff --git a/kclvm/tools/src/LSP/src/completion.rs b/kclvm/tools/src/LSP/src/completion.rs index 540c589d5..467068c3a 100644 --- a/kclvm/tools/src/LSP/src/completion.rs +++ b/kclvm/tools/src/LSP/src/completion.rs @@ -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!( @@ -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!( @@ -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())), diff --git a/kclvm/tools/src/LSP/src/hover.rs b/kclvm/tools/src/LSP/src/hover.rs index 537b59b09..b9cd8f6f3 100644 --- a/kclvm/tools/src/LSP/src/hover.rs +++ b/kclvm/tools/src/LSP/src/hover.rs @@ -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; @@ -17,6 +17,7 @@ pub(crate) fn hover( gs: &GlobalState, ) -> Option { let mut docs: Vec = 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) { @@ -36,7 +37,9 @@ pub(crate) fn hover( // attr2? type // ``` let schema_ty = ty.into_schema_type(); - docs.push(schema_ty.schema_ty_signature_str()); + let (pkgpath, rest_sign) = schema_ty.schema_ty_signature_str(); + pkg_path = pkgpath; + docs.push(rest_sign); if !schema_ty.doc.is_empty() { docs.push(schema_ty.doc.clone()); } @@ -120,26 +123,37 @@ 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) -> Option { +fn docs_to_hover(docs: Vec, pkg_path: String) -> Option { match docs.len() { 0 => None, 1 => Some(Hover { - contents: HoverContents::Scalar(MarkedString::String(docs[0].clone())), - range: None, - }), - _ => Some(Hover { - contents: HoverContents::Array( - docs.iter() - .map(|doc| MarkedString::String(doc.clone())) - .collect(), - ), + contents: HoverContents::Scalar(MarkedString::LanguageString(LanguageString { + language: "KCL".to_owned(), + value: docs[0].clone(), + })), range: None, }), + _ => { + 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(), + }) + })); + Some(Hover { + contents: HoverContents::Array(all_docs), + range: None, + }) + } } } @@ -186,7 +200,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; @@ -213,12 +227,15 @@ 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, "hover doc test"); + } + if let MarkedString::String(s) = vec[3].clone() { assert_eq!(s, "Attributes:\n\nname: str\n\nage: int"); } } @@ -251,9 +268,9 @@ 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 { @@ -261,15 +278,24 @@ mod tests { 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"), @@ -291,12 +317,15 @@ 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"); } if let MarkedString::String(s) = vec[2].clone() { + assert_eq!(s, "hover doc test"); + } + if let MarkedString::String(s) = vec[3].clone() { assert_eq!(s, "Attributes:\n\nname: str\n\nage?: int"); } } @@ -499,11 +528,14 @@ mod tests { let got = hover(&program, &pos, &gs).unwrap(); match got.contents { lsp_types::HoverContents::Array(vec) => { - assert_eq!(vec.len(), 2); + assert_eq!(vec.len(), 3); 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, "schema Fib"); + } + if let MarkedString::String(s) = vec[2].clone() { assert_eq!(s, "Attributes:\n\nn: int\n\nvalue: int"); } } @@ -561,11 +593,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) @@ -599,8 +636,15 @@ 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)".to_string(), + }), + MarkedString::LanguageString(LanguageString { + language: "KCL".to_string(), + value: "Attributes:\n\nname: str\n\nage: int".to_string(), + }), ]; match got.contents { diff --git a/kclvm/tools/src/LSP/src/tests.rs b/kclvm/tools/src/LSP/src/tests.rs index 8e750d8bb..9cdee4e36 100644 --- a/kclvm/tools/src/LSP/src/tests.rs +++ b/kclvm/tools/src/LSP/src/tests.rs @@ -25,6 +25,7 @@ use lsp_types::Hover; use lsp_types::HoverContents; use lsp_types::HoverParams; use lsp_types::InitializeParams; +use lsp_types::LanguageString; use lsp_types::MarkedString; use lsp_types::PublishDiagnosticsParams; use lsp_types::ReferenceContext; @@ -1169,9 +1170,19 @@ fn hover_test() { res.result.unwrap(), to_json(Hover { contents: HoverContents::Array(vec![ - MarkedString::String("__main__\n\nschema Person".to_string()), - MarkedString::String("hover doc test".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 Person".to_string() + }), + MarkedString::LanguageString(LanguageString { + language: "KCL".to_string(), + value: "hover doc test".to_string() + }), + MarkedString::LanguageString(LanguageString { + language: "KCL".to_string(), + value: "Attributes:\n\nname: str\n\nage?: int".to_string() + }), ]), range: None }) @@ -1225,7 +1236,10 @@ 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::LanguageString(LanguageString { + language: "KCL".to_string(), + value: "images: [str]".to_string(), + })), range: None }) .unwrap() @@ -1663,12 +1677,21 @@ fn konfig_hover_test_main() { let got = hover(&program, &pos, &gs).unwrap(); match got.contents { HoverContents::Array(arr) => { - let expect: Vec = ["base.pkg.kusion_models.kube.frontend\n\nschema Server", - "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"] - .iter() - .map(|s| MarkedString::String(s.to_string())) - .collect(); + let expect: Vec = vec![ + MarkedString::String("base.pkg.kusion_models.kube.frontend".to_string()), + MarkedString::LanguageString(LanguageString { + language: "KCL".to_string(), + value: "schema Server".to_string(), + }), + MarkedString::LanguageString(LanguageString { + language: "KCL".to_string(), + value: "Server is abstaction of Deployment and StatefulSet.".to_string(), + }), + MarkedString::LanguageString(LanguageString { + language: "KCL".to_string(), + value: "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".to_string(), + }), + ]; assert_eq!(expect, arr); } _ => unreachable!("test error"), @@ -1683,13 +1706,16 @@ fn konfig_hover_test_main() { let got = hover(&program, &pos, &gs).unwrap(); match got.contents { HoverContents::Array(arr) => { - let expect: Vec = [ - "schedulingStrategy: SchedulingStrategy", - "SchedulingStrategy represents scheduling strategy.", - ] - .iter() - .map(|s| MarkedString::String(s.to_string())) - .collect(); + let expect: Vec = vec![ + MarkedString::LanguageString(LanguageString { + language: "KCL".to_string(), + value: "schedulingStrategy: SchedulingStrategy".to_string(), + }), + MarkedString::LanguageString(LanguageString { + language: "KCL".to_string(), + value: "SchedulingStrategy represents scheduling strategy.".to_string(), + }), + ]; assert_eq!(expect, arr); } _ => unreachable!("test error"), @@ -1706,7 +1732,10 @@ fn konfig_hover_test_main() { HoverContents::Scalar(s) => { assert_eq!( s, - MarkedString::String("appConfiguration: Server".to_string()) + MarkedString::LanguageString(LanguageString { + language: "KCL".to_string(), + value: "appConfiguration: Server".to_string(), + }) ); } _ => unreachable!("test error"),